@@ -24,7 +24,7 @@ import (
2424 "time"
2525
2626 "github.com/cskr/pubsub"
27- "github.com/ethereum/go-ethereum"
27+ ethereum "github.com/ethereum/go-ethereum"
2828 "github.com/ethereum/go-ethereum/common"
2929 "github.com/ethereum/go-ethereum/core/types"
3030 "github.com/ethereum/go-ethereum/ethclient"
@@ -619,30 +619,30 @@ type Header struct {
619619// SubscribeNewHead subscribes to notifications about the current blockchain head
620620// on the given channel.
621621func (mc * Client ) SubscribeNewHead (ctx context.Context , ch chan <- * Header ) (ethereum.Subscription , error ) {
622- clientsMap := mc .rpcClientMap .Map ()
623- lens := len (clientsMap )
622+ ids := mc .rpcClientMap .Ids ()
623+ lens := len (ids )
624624 if lens == 0 {
625625 return nil , ErrNoEthClient
626626 }
627627
628628 var subscribeNewHeadWg sync.WaitGroup
629629
630630 cctx , cancel := context .WithCancel (ctx )
631- for url := range clientsMap {
631+ for _ , id := range ids {
632632 subscribeNewHeadWg .Add (1 )
633- go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , url , ch )
633+ go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , id , ch )
634634 }
635635
636636 newClientCh := mc .pubSub .Sub (newAvailableClientTopic )
637- // handle new clients comes
637+ // handle new clients come
638638 go func () {
639639 defer mc .pubSub .Unsub (newClientCh , newAvailableClientTopic )
640640 for {
641641 select {
642642 case newC := <- newClientCh :
643- url := newC .(string )
643+ id := newC .(uint64 )
644644 subscribeNewHeadWg .Add (1 )
645- go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , url , ch )
645+ go mc .subscribeNewHead (cctx , & subscribeNewHeadWg , id , ch )
646646 case <- cctx .Done ():
647647 return
648648 }
@@ -657,46 +657,66 @@ func (mc *Client) SubscribeNewHead(ctx context.Context, ch chan<- *Header) (ethe
657657 }), nil
658658}
659659
660- func (mc * Client ) subscribeNewHead (ctx context.Context , wg * sync.WaitGroup , url string , ch chan <- * Header ) error {
660+ func (mc * Client ) subscribeNewHead (ctx context.Context , wg * sync.WaitGroup , id uint64 , ch chan <- * Header ) error {
661+ logger := log .New ("id" , id )
661662 defer wg .Done ()
662663
664+ retryTimer := time .NewTimer (0 )
665+ defer retryTimer .Stop ()
666+
663667 for {
664- rc := mc .rpcClientMap .Get ( url )
668+ url , rc := mc .rpcClientMap .GetById ( id )
665669 if rc == nil {
666- log .Trace ("EthClient has been removed" , "url" , url )
670+ logger .Trace ("EthClient has been removed" )
671+ return nil
672+ }
673+ subLogger := logger .New ("url" , url )
674+ // If we have error, we need to retry
675+ err := doSubscribe (ctx , subLogger , rc , ch )
676+ if err == nil {
667677 return nil
668678 }
669679
670- headerCh := make (chan * types.Header )
671- c := ethclient .NewClient (rc )
672- sub , err := c .SubscribeNewHead (ctx , headerCh )
673- if err != nil {
674- log .Warn ("Failed to subscribe new head" , "url" , url , "err" , err )
675- } else {
676- WAIT_NEW_HEADER:
677- for {
678- select {
679- case header := <- headerCh :
680- h := & Header {
681- Client : rc ,
682- Header : header ,
683- }
684- select {
685- case ch <- h :
686- case <- ctx .Done ():
687- return nil
688- }
689- case err := <- sub .Err ():
690- log .Warn ("Failed during subscription" , "url" , url , "err" , err )
691- break WAIT_NEW_HEADER
692- case <- ctx .Done ():
693- return nil
694- }
680+ // reset timer with retryPeriod
681+ retryTimer .Reset (retryPeriod )
682+ select {
683+ case <- retryTimer .C :
684+ case <- ctx .Done ():
685+ return nil
686+ }
687+ subLogger .Trace ("Retry to subscribe new head" )
688+ }
689+ }
690+
691+ func doSubscribe (ctx context.Context , logger log.Logger , rc * rpc.Client , ch chan <- * Header ) error {
692+ headerCh := make (chan * types.Header )
693+ c := ethclient .NewClient (rc )
694+ subCtx , cancel := context .WithCancel (ctx )
695+ defer cancel ()
696+
697+ sub , err := c .SubscribeNewHead (subCtx , headerCh )
698+ if err != nil {
699+ logger .Warn ("Failed to subscribe new head" , "err" , err )
700+ return err
701+ }
702+ for {
703+ select {
704+ case header := <- headerCh :
705+ h := & Header {
706+ Client : rc ,
707+ Header : header ,
695708 }
709+ select {
710+ case ch <- h :
711+ case <- subCtx .Done ():
712+ return nil
713+ }
714+ case err := <- sub .Err ():
715+ logger .Warn ("Failed during subscription" , "err" , err )
716+ return err
717+ case <- subCtx .Done ():
718+ return nil
696719 }
697- // retry subscribe after retryPeriod
698- time .Sleep (retryPeriod )
699- log .Trace ("Retry to subscribe new head" , "url" , url )
700720 }
701721}
702722
@@ -788,8 +808,8 @@ func (mc *Client) DialClients(ctx context.Context) {
788808 for i := 0 ; i < len (urls ); i ++ {
789809 dialed := <- dialCh
790810 if dialed .client != nil {
791- mc .rpcClientMap .Replace (dialed .url , dialed .client )
792- mc .pubSub .Pub (dialed . url , newAvailableClientTopic )
811+ id := mc .rpcClientMap .Replace (dialed .url , dialed .client )
812+ mc .pubSub .Pub (id , newAvailableClientTopic )
793813 }
794814 }
795815}
0 commit comments