diff --git a/api/profiler.go b/api/profiler.go index 973ba349b..efb366693 100644 --- a/api/profiler.go +++ b/api/profiler.go @@ -9,6 +9,8 @@ import ( "strconv" "time" + "github.com/rs/zerolog/log" + "github.com/onflow/flow-go/module/component" "github.com/onflow/flow-go/module/irrecoverable" @@ -16,11 +18,11 @@ import ( ) type ProfileServer struct { + component.Component + log zerolog.Logger server *http.Server endpoint string - - startupCompleted chan struct{} } var _ component.Component = (*ProfileServer)(nil) @@ -31,70 +33,69 @@ func NewProfileServer( port int, ) *ProfileServer { endpoint := net.JoinHostPort(host, strconv.Itoa(port)) - return &ProfileServer{ - log: logger, - server: &http.Server{Addr: endpoint}, - endpoint: endpoint, - startupCompleted: make(chan struct{}), + + s := &ProfileServer{ + log: logger, + server: &http.Server{Addr: endpoint}, + endpoint: endpoint, } + + s.Component = component.NewComponentManagerBuilder(). + AddWorker(s.serve). + AddWorker(s.shutdownOnContextDone). + Build() + + return s } -func (s *ProfileServer) Start(ctx irrecoverable.SignalerContext) { - defer close(s.startupCompleted) +func (s *ProfileServer) serve(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { + s.log.Info().Msg("starting profiler server on address") + + l, err := net.Listen("tcp", s.endpoint) + if err != nil { + s.log.Err(err).Msg("failed to start the metrics server") + ctx.Throw(err) + return + } + + ready() + // pass the signaler context to the server so that the signaler context + // can control the server's lifetime s.server.BaseContext = func(_ net.Listener) context.Context { return ctx } - go func() { - s.log.Info().Msgf("Profiler server started: %s", s.endpoint) - - if err := s.server.ListenAndServe(); err != nil { - // http.ErrServerClosed is returned when Close or Shutdown is called - // we don't consider this an error, so print this with debug level instead - if errors.Is(err, http.ErrServerClosed) { - s.log.Debug().Err(err).Msg("Profiler server shutdown") - } else { - s.log.Err(err).Msg("error running profiler server") - } + err = s.server.Serve(l) // blocking call + if err != nil { + if errors.Is(err, http.ErrServerClosed) { + return } - }() -} - -func (s *ProfileServer) Ready() <-chan struct{} { - ready := make(chan struct{}) - - go func() { - <-s.startupCompleted - close(ready) - }() - return ready + log.Err(err).Msg("fatal error in the metrics server") + ctx.Throw(err) + } } -func (s *ProfileServer) Done() <-chan struct{} { - done := make(chan struct{}) - go func() { - <-s.startupCompleted - defer close(done) +func (s *ProfileServer) shutdownOnContextDone(ictx irrecoverable.SignalerContext, ready component.ReadyFunc) { + ready() + <-ictx.Done() - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() - err := s.server.Shutdown(ctx) - if err == nil { - s.log.Info().Msg("Profiler server graceful shutdown completed") - } + err := s.server.Shutdown(ctx) + if err == nil { + s.log.Info().Msg("Profiler server graceful shutdown completed") + } - if errors.Is(err, ctx.Err()) { - s.log.Warn().Msg("Profiler server graceful shutdown timed out") - err := s.server.Close() - if err != nil { - s.log.Err(err).Msg("error closing profiler server") - } - } else { - s.log.Err(err).Msg("error shutting down profiler server") + if errors.Is(err, ctx.Err()) { + s.log.Warn().Msg("Profiler server graceful shutdown timed out") + err := s.server.Close() + if err != nil { + s.log.Err(err).Msg("error closing profiler server") } - }() - return done + } else { + s.log.Err(err).Msg("error shutting down profiler server") + } } diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index b521a973f..696a584e1 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -148,10 +148,12 @@ func (fnb *EVMGatewayNodeBuilder) initDB() error { if err := fnb.DB.Close(); err != nil { return fmt.Errorf("error closing pebble database: %w", err) } + + fnb.Logger.Info().Msg("database has been closed") return nil }) - return err + return nil } func (fnb *EVMGatewayNodeBuilder) Component(name string, f cmd.ReadyDoneFactory[config.Config]) *EVMGatewayNodeBuilder { @@ -173,7 +175,6 @@ func (fnb *EVMGatewayNodeBuilder) postShutdown() error { errs = multierror.Append(errs, err) } } - fnb.Logger.Info().Msg("database has been closed") return errs.ErrorOrNil() } @@ -206,11 +207,11 @@ func (fnb *EVMGatewayNodeBuilder) Initialize() error { func (fnb *EVMGatewayNodeBuilder) LoadComponentsAndModules() { fnb.initPublishers() + fnb.Component("Profiler Server", fnb.profilerServerComponent) + fnb.Component("Metrics Server", fnb.metricsServerComponent) fnb.Component("Key Store", fnb.initKeyStore) fnb.Component("API Server", fnb.apiServerComponent) fnb.Component("Event Ingestion Engine", fnb.eventIngestionEngineComponent) - fnb.Component("Metrics Server", fnb.metricsServerComponent) - fnb.Component("Profiler Server", fnb.profilerServerComponent) } func (fnb *EVMGatewayNodeBuilder) metricsServerComponent(config config.Config) (module.ReadyDoneAware, error) { @@ -359,30 +360,30 @@ func (fnb *EVMGatewayNodeBuilder) eventIngestionEngineComponent(cfg config.Confi l.Info().Msg("bootstrap starting event ingestion") // get latest cadence block from the network and the database - latestCadenceBlock, err := fnb.Client.GetLatestBlock(context.Background(), true) + gatewayLatestBlock, err := fnb.Client.GetLatestBlock(context.Background(), true) if err != nil { return nil, fmt.Errorf("failed to get latest cadence block: %w", err) } - latestCadenceHeight, err := fnb.Storages.Blocks.LatestCadenceHeight() + chainLatestHeight, err := fnb.Storages.Blocks.LatestCadenceHeight() if err != nil { return nil, err } // make sure the provided block to start the indexing can be loaded - _, err = fnb.Client.GetBlockHeaderByHeight(context.Background(), latestCadenceHeight) + _, err = fnb.Client.GetBlockHeaderByHeight(context.Background(), chainLatestHeight) if err != nil { return nil, fmt.Errorf( "failed to get provided cadence height %d: %w", - latestCadenceHeight, + chainLatestHeight, err, ) } l.Info(). - Uint64("start-cadence-height", latestCadenceHeight). - Uint64("latest-cadence-height", latestCadenceBlock.Height). - Uint64("missed-heights", latestCadenceBlock.Height-latestCadenceHeight). + Uint64("chain-cadence-height", chainLatestHeight). + Uint64("gateway-cadence-height", gatewayLatestBlock.Height). + Uint64("missed-heights", gatewayLatestBlock.Height-chainLatestHeight). Msg("indexing cadence height information") chainID := cfg.FlowNetworkID @@ -393,7 +394,7 @@ func (fnb *EVMGatewayNodeBuilder) eventIngestionEngineComponent(cfg config.Confi fnb.Client, chainID, fnb.Keystore, - latestCadenceHeight, + chainLatestHeight, ) callTracerCollector, err := replayer.NewCallTracerCollector(fnb.Logger) diff --git a/cmd/run/cmd.go b/cmd/run/cmd.go index c590a93af..1cc988806 100644 --- a/cmd/run/cmd.go +++ b/cmd/run/cmd.go @@ -39,14 +39,14 @@ var Cmd = &cobra.Command{ builder := bootstrap.NewEVMGatewayNodeBuilder(cfg) if err := builder.Initialize(); err != nil { - builder.Logger.Fatal().Err(err).Send() + builder.Logger.Fatal().Err(err).Msg("failed to initialize") } builder.LoadComponentsAndModules() node, err := builder.Build() if err != nil { - builder.Logger.Fatal().Err(err).Send() + builder.Logger.Fatal().Err(err).Msg("failed to build node") } node.Run(command.Context()) return nil diff --git a/go.mod b/go.mod index 3cb7df86d..abe9f4155 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/onflow/atree v0.8.0 github.com/onflow/cadence v1.2.2 - github.com/onflow/flow-go v0.38.0-preview.0.4.0.20241213150609-85fd812a7e49 + github.com/onflow/flow-go v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4 github.com/onflow/flow-go-sdk v1.2.3 github.com/onflow/go-ethereum v1.14.7 github.com/prometheus/client_golang v1.18.0 diff --git a/go.sum b/go.sum index bd23d04c6..db2915323 100644 --- a/go.sum +++ b/go.sum @@ -743,8 +743,8 @@ github.com/onflow/flow-ft/lib/go/contracts v1.0.1 h1:Ts5ob+CoCY2EjEd0W6vdLJ7hLL3 github.com/onflow/flow-ft/lib/go/contracts v1.0.1/go.mod h1:PwsL8fC81cjnUnTfmyL/HOIyHnyaw/JA474Wfj2tl6A= github.com/onflow/flow-ft/lib/go/templates v1.0.1 h1:FDYKAiGowABtoMNusLuRCILIZDtVqJ/5tYI4VkF5zfM= github.com/onflow/flow-ft/lib/go/templates v1.0.1/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE= -github.com/onflow/flow-go v0.38.0-preview.0.4.0.20241213150609-85fd812a7e49 h1:kcAoHB/uEGP3wTJcv2aVtCHSgwY0bdn8qjw7GvvHfM8= -github.com/onflow/flow-go v0.38.0-preview.0.4.0.20241213150609-85fd812a7e49/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0= +github.com/onflow/flow-go v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4 h1:PSxMlqAgTzeTb/J6nknx3q74MNtUFnKWfWEneE+HLX8= +github.com/onflow/flow-go v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0= github.com/onflow/flow-go-sdk v1.2.3 h1:jb+0dIXBO12Zt8x3c2xDXYPv6k3sRTUvhe59M+EcXTI= github.com/onflow/flow-go-sdk v1.2.3/go.mod h1:jMaffBTlAIdutx+pBhRIigLZFIBYSDDST0Uax1rW2qo= github.com/onflow/flow-nft/lib/go/contracts v1.2.2 h1:XFERNVUDGbZ4ViZjt7P1cGD80mO1PzUJYPfdhXFsGbQ= diff --git a/services/ingestion/engine.go b/services/ingestion/engine.go index 94535c6af..339861b26 100644 --- a/services/ingestion/engine.go +++ b/services/ingestion/engine.go @@ -129,6 +129,7 @@ func (e *Engine) run(ctx irrecoverable.SignalerContext, ready component.ReadyFun return } if events.Err != nil { + ctx.Throw(fmt.Errorf("failure in event subscription with: %w", events.Err)) return } @@ -136,6 +137,7 @@ func (e *Engine) run(ctx irrecoverable.SignalerContext, ready component.ReadyFun if err != nil { e.log.Error().Err(err).Msg("failed to process EVM events") ctx.Throw(err) + return } } } diff --git a/tests/go.mod b/tests/go.mod index 15feb0f9d..957b3914b 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -6,9 +6,9 @@ require ( github.com/goccy/go-json v0.10.2 github.com/onflow/cadence v1.2.2 github.com/onflow/crypto v0.25.2 - github.com/onflow/flow-emulator v1.1.1-0.20241216151608-ed31000dff47 + github.com/onflow/flow-emulator v1.1.1-0.20250103150158-e029ea3471fe github.com/onflow/flow-evm-gateway v0.0.0-20240201154855-4d4d3d3f19c7 - github.com/onflow/flow-go v0.38.0-preview.0.4.0.20241213150609-85fd812a7e49 + github.com/onflow/flow-go v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4 github.com/onflow/flow-go-sdk v1.2.3 github.com/onflow/go-ethereum v1.14.7 github.com/rs/zerolog v1.33.0 diff --git a/tests/go.sum b/tests/go.sum index 20299d662..08c27c08d 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -906,14 +906,14 @@ github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 h1:R86HaOuk6vpuECZ github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0/go.mod h1:9asTBnB6Tw2UlVVtQKyS/egYv3xr4zVlJnJ75z1dfac= github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0 h1:u2DAG8pk0xFH7TwS70t1gSZ/FtIIZWMSNyiu4SeXBYg= github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0/go.mod h1:pN768Al/wLRlf3bwugv9TyxniqJxMu4sxnX9eQJam64= -github.com/onflow/flow-emulator v1.1.1-0.20241216151608-ed31000dff47 h1:OjYlGVC+rLxP7rCS74U0aqilChCjJrtvU52Bt7rZ62w= -github.com/onflow/flow-emulator v1.1.1-0.20241216151608-ed31000dff47/go.mod h1:45cGyqSvI7o/oOHuYZkMc917f5JSKiCBQh30NV3w6Ks= +github.com/onflow/flow-emulator v1.1.1-0.20250103150158-e029ea3471fe h1:0O/VrpF4ujhCqj5pzYmrb5qvghzf+1fxVxbp4jlneM4= +github.com/onflow/flow-emulator v1.1.1-0.20250103150158-e029ea3471fe/go.mod h1:6Uj/ftISX4Su7blfRKTdENdyr29XAp364lT1ESgrh7s= github.com/onflow/flow-ft/lib/go/contracts v1.0.1 h1:Ts5ob+CoCY2EjEd0W6vdLJ7hLL3SsEftzXG2JlmSe24= github.com/onflow/flow-ft/lib/go/contracts v1.0.1/go.mod h1:PwsL8fC81cjnUnTfmyL/HOIyHnyaw/JA474Wfj2tl6A= github.com/onflow/flow-ft/lib/go/templates v1.0.1 h1:FDYKAiGowABtoMNusLuRCILIZDtVqJ/5tYI4VkF5zfM= github.com/onflow/flow-ft/lib/go/templates v1.0.1/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE= -github.com/onflow/flow-go v0.38.0-preview.0.4.0.20241213150609-85fd812a7e49 h1:kcAoHB/uEGP3wTJcv2aVtCHSgwY0bdn8qjw7GvvHfM8= -github.com/onflow/flow-go v0.38.0-preview.0.4.0.20241213150609-85fd812a7e49/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0= +github.com/onflow/flow-go v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4 h1:PSxMlqAgTzeTb/J6nknx3q74MNtUFnKWfWEneE+HLX8= +github.com/onflow/flow-go v0.38.0-preview.0.4.0.20250102180624-72adf9e522c4/go.mod h1:c4ubAQ2WIMYY/TOaBvbajROEFWv2HwhKeGOsEdLPIM0= github.com/onflow/flow-go-sdk v1.2.3 h1:jb+0dIXBO12Zt8x3c2xDXYPv6k3sRTUvhe59M+EcXTI= github.com/onflow/flow-go-sdk v1.2.3/go.mod h1:jMaffBTlAIdutx+pBhRIigLZFIBYSDDST0Uax1rW2qo= github.com/onflow/flow-nft/lib/go/contracts v1.2.2 h1:XFERNVUDGbZ4ViZjt7P1cGD80mO1PzUJYPfdhXFsGbQ= diff --git a/tests/helpers.go b/tests/helpers.go index 58923ab54..47e5e3366 100644 --- a/tests/helpers.go +++ b/tests/helpers.go @@ -195,6 +195,7 @@ func startGateway(t *testing.T, ctx context.Context, cfg config.Config) { node, err := builder.Build() require.NoError(t, err) go node.Run(ctx) + <-node.Ready() } // executeTest will run the provided JS test file using mocha