@@ -13,15 +13,15 @@ import (
1313
1414 "github.com/ava-labs/coreth/plugin/evm/message"
1515
16- synccommon "github.com/ava-labs/coreth/sync"
16+ syncpkg "github.com/ava-labs/coreth/sync"
1717)
1818
1919var errSyncerAlreadyRegistered = errors .New ("syncer already registered" )
2020
2121// SyncerTask represents a single syncer with its name for identification.
2222type SyncerTask struct {
2323 name string
24- syncer synccommon .Syncer
24+ syncer syncpkg .Syncer
2525}
2626
2727// SyncerRegistry manages a collection of syncers for sequential execution.
@@ -39,7 +39,7 @@ func NewSyncerRegistry() *SyncerRegistry {
3939
4040// Register adds a syncer to the registry.
4141// Returns an error if a syncer with the same name is already registered.
42- func (r * SyncerRegistry ) Register (syncer synccommon .Syncer ) error {
42+ func (r * SyncerRegistry ) Register (syncer syncpkg .Syncer ) error {
4343 id := syncer .ID ()
4444 if r .registeredNames [id ] {
4545 return fmt .Errorf ("%w with id '%s'" , errSyncerAlreadyRegistered , id )
@@ -51,22 +51,46 @@ func (r *SyncerRegistry) Register(syncer synccommon.Syncer) error {
5151 return nil
5252}
5353
54- // RunSyncerTasks executes all registered syncers.
55- // The provided summary is used only for logging to decouple from concrete client types.
54+ // RunSyncerTasks executes all registered syncers synchronously.
5655func (r * SyncerRegistry ) RunSyncerTasks (ctx context.Context , summary message.Syncable ) error {
56+ // Early return if context is already canceled (e.g., during shutdown).
57+ if err := ctx .Err (); err != nil {
58+ return err
59+ }
60+
61+ g := r .StartAsync (ctx , summary )
62+
63+ if err := g .Wait (); err != nil {
64+ return err
65+ }
66+
67+ log .Info ("all syncers completed successfully" , "count" , len (r .syncers ), "summary" , summary .GetBlockHash ().Hex ())
68+
69+ return nil
70+ }
71+
72+ // StartAsync launches all registered syncers and returns an [errgroup.Group]
73+ // whose Wait() completes when all syncers exit. The context returned will be
74+ // cancelled when any syncer fails, propagating shutdown to the others.
75+ func (r * SyncerRegistry ) StartAsync (ctx context.Context , summary message.Syncable ) * errgroup.Group {
76+ g , egCtx := errgroup .WithContext (ctx )
77+
5778 if len (r .syncers ) == 0 {
58- return nil
79+ return g
5980 }
6081
6182 summaryBlockHashHex := summary .GetBlockHash ().Hex ()
6283 blockHeight := summary .Height ()
6384
64- g , ctx := errgroup .WithContext (ctx )
65-
6685 for _ , task := range r .syncers {
6786 g .Go (func () error {
6887 log .Info ("starting syncer" , "name" , task .name , "summary" , summaryBlockHashHex , "height" , blockHeight )
69- if err := task .syncer .Sync (ctx ); err != nil {
88+ if err := task .syncer .Sync (egCtx ); err != nil {
89+ // Context cancellation during shutdown is expected.
90+ if errors .Is (err , context .Canceled ) || errors .Is (err , context .DeadlineExceeded ) {
91+ log .Info ("syncer cancelled" , "name" , task .name , "summary" , summaryBlockHashHex , "height" , blockHeight )
92+ return err
93+ }
7094 log .Error ("failed syncing" , "name" , task .name , "summary" , summaryBlockHashHex , "height" , blockHeight , "err" , err )
7195 return fmt .Errorf ("%s failed: %w" , task .name , err )
7296 }
@@ -76,11 +100,5 @@ func (r *SyncerRegistry) RunSyncerTasks(ctx context.Context, summary message.Syn
76100 })
77101 }
78102
79- if err := g .Wait (); err != nil {
80- return err
81- }
82-
83- log .Info ("all syncers completed successfully" , "count" , len (r .syncers ), "summary" , summaryBlockHashHex )
84-
85- return nil
103+ return g
86104}
0 commit comments