imp(server): Add query-only mode flag for gRPC (#1360)
* add grpc only mode flag * add change log * add tmNode nil check * only flag to modes * fix close for query mode * fix hint * keep grpc-only & json-rpc-only * rm space * mv apiSrv close * mv cpuProfileCleanup * mv tmNode stop * disable indexer on query only which need tm client on start * update nix * revert json-rpc-only change
This commit is contained in:
parent
db94d8ec23
commit
236ca33c53
@ -60,6 +60,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (ledger) [#1277](https://github.com/evmos/ethermint/pull/1277) Add Ledger preprocessing transaction hook for EIP-712-signed Cosmos payloads.
|
||||
* (rpc) [#1296](https://github.com/evmos/ethermint/pull/1296) Add RPC Backend unit tests.
|
||||
* (rpc) [#1352](https://github.com/evmos/ethermint/pull/1352) Make the grpc queries run concurrently, don't block the consensus state machine.
|
||||
* (cli) [#1360](https://github.com/evmos/ethermint/pull/1360) Introduce a new `grpc-only` flag, such that when enabled, will start the node in a query-only mode. Note, gRPC MUST be enabled with this flag.
|
||||
* (rpc) [#1378](https://github.com/evmos/ethermint/pull/1378) Add support for EVM RPC metrics
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -20,6 +20,7 @@ const (
|
||||
|
||||
// GRPC-related flags.
|
||||
const (
|
||||
GRPCOnly = "grpc-only"
|
||||
GRPCEnable = "grpc.enable"
|
||||
GRPCAddress = "grpc.address"
|
||||
GRPCWebEnable = "grpc-web.enable"
|
||||
|
173
server/start.go
173
server/start.go
@ -150,6 +150,7 @@ which accepts a path for the resulting pprof file.
|
||||
cmd.Flags().Uint64(server.FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks")
|
||||
cmd.Flags().String(srvflags.AppDBBackend, "", "The type of database for application and snapshots databases")
|
||||
|
||||
cmd.Flags().Bool(srvflags.GRPCOnly, false, "Start the node in gRPC query only mode without Tendermint process")
|
||||
cmd.Flags().Bool(srvflags.GRPCEnable, true, "Define if the gRPC server should be enabled")
|
||||
cmd.Flags().String(srvflags.GRPCAddress, serverconfig.DefaultGRPCAddress, "the gRPC server address to listen on")
|
||||
cmd.Flags().Bool(srvflags.GRPCWebEnable, true, "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled.)")
|
||||
@ -158,7 +159,7 @@ which accepts a path for the resulting pprof file.
|
||||
cmd.Flags().Bool(srvflags.RPCEnable, false, "Defines if Cosmos-sdk REST server should be enabled")
|
||||
cmd.Flags().Bool(srvflags.EnabledUnsafeCors, false, "Defines if CORS should be enabled (unsafe - use it at your own risk)")
|
||||
|
||||
cmd.Flags().Bool(srvflags.JSONRPCEnable, true, "Define if the gRPC server should be enabled")
|
||||
cmd.Flags().Bool(srvflags.JSONRPCEnable, true, "Define if the JSON-RPC server should be enabled")
|
||||
cmd.Flags().StringSlice(srvflags.JSONRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled")
|
||||
cmd.Flags().String(srvflags.JSONRPCAddress, config.DefaultJSONRPCAddress, "the JSON-RPC server address to listen on")
|
||||
cmd.Flags().String(srvflags.JSONWsAddress, config.DefaultJSONRPCWsAddress, "the JSON-RPC WS server address to listen on")
|
||||
@ -239,8 +240,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
cfg := ctx.Config
|
||||
home := cfg.RootDir
|
||||
logger := ctx.Logger
|
||||
var cpuProfileCleanup func() error
|
||||
|
||||
if cpuProfile := ctx.Viper.GetString(srvflags.CPUProfile); cpuProfile != "" {
|
||||
fp, err := ethdebug.ExpandHome(cpuProfile)
|
||||
if err != nil {
|
||||
@ -257,15 +256,13 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
return err
|
||||
}
|
||||
|
||||
cpuProfileCleanup = func() error {
|
||||
defer func() {
|
||||
ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile)
|
||||
pprof.StopCPUProfile()
|
||||
if err := f.Close(); err != nil {
|
||||
logger.Error("failed to close CPU profiler file", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore)
|
||||
@ -313,30 +310,47 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
}
|
||||
|
||||
genDocProvider := node.DefaultGenesisDocProviderFunc(cfg)
|
||||
tmNode, err := node.NewNode(
|
||||
cfg,
|
||||
pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()),
|
||||
nodeKey,
|
||||
proxy.NewLocalClientCreator(app),
|
||||
genDocProvider,
|
||||
node.DefaultDBProvider,
|
||||
node.DefaultMetricsProvider(cfg.Instrumentation),
|
||||
ctx.Logger.With("server", "node"),
|
||||
var (
|
||||
tmNode *node.Node
|
||||
gRPCOnly = ctx.Viper.GetBool(srvflags.GRPCOnly)
|
||||
)
|
||||
if err != nil {
|
||||
logger.Error("failed init node", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
if gRPCOnly {
|
||||
ctx.Logger.Info("starting node in query only mode; Tendermint is disabled")
|
||||
config.GRPC.Enable = true
|
||||
config.JSONRPC.EnableIndexer = false
|
||||
} else {
|
||||
tmNode, err = node.NewNode(
|
||||
cfg,
|
||||
pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()),
|
||||
nodeKey,
|
||||
proxy.NewLocalClientCreator(app),
|
||||
genDocProvider,
|
||||
node.DefaultDBProvider,
|
||||
node.DefaultMetricsProvider(cfg.Instrumentation),
|
||||
ctx.Logger.With("server", "node"),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Error("failed init node", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tmNode.Start(); err != nil {
|
||||
logger.Error("failed start tendermint server", "error", err.Error())
|
||||
return err
|
||||
if err := tmNode.Start(); err != nil {
|
||||
logger.Error("failed start tendermint server", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if tmNode.IsRunning() {
|
||||
_ = tmNode.Stop()
|
||||
}
|
||||
logger.Info("Bye!")
|
||||
}()
|
||||
}
|
||||
|
||||
// Add the tx service to the gRPC router. We only need to register this
|
||||
// service if API or gRPC or JSONRPC is enabled, and avoid doing so in the general
|
||||
// case, because it spawns a new local tendermint RPC client.
|
||||
if config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable || config.JSONRPC.EnableIndexer {
|
||||
if (config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable || config.JSONRPC.EnableIndexer) && tmNode != nil {
|
||||
clientCtx = clientCtx.WithClient(local.New(tmNode))
|
||||
|
||||
app.RegisterTxService(clientCtx)
|
||||
@ -429,7 +443,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
apiSrv = api.New(clientCtx, ctx.Logger.With("server", "api"))
|
||||
app.RegisterAPIRoutes(apiSrv, config.API)
|
||||
errCh := make(chan error)
|
||||
|
||||
go func() {
|
||||
if err := apiSrv.Start(config.Config); err != nil {
|
||||
errCh <- err
|
||||
@ -441,6 +454,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
return err
|
||||
case <-time.After(types.ServerStartTime): // assume server started successfully
|
||||
}
|
||||
defer apiSrv.Close()
|
||||
}
|
||||
|
||||
var (
|
||||
@ -452,15 +466,62 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer grpcSrv.Stop()
|
||||
if config.GRPCWeb.Enable {
|
||||
grpcWebSrv, err = servergrpc.StartGRPCWeb(grpcSrv, config.Config)
|
||||
if err != nil {
|
||||
ctx.Logger.Error("failed to start grpc-web http server", "error", err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := grpcWebSrv.Close(); err != nil {
|
||||
logger.Error("failed to close the grpcWebSrc", "error", err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
httpSrv *http.Server
|
||||
httpSrvDone chan struct{}
|
||||
)
|
||||
|
||||
if config.JSONRPC.Enable {
|
||||
genDoc, err := genDocProvider()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientCtx := clientCtx.WithChainID(genDoc.ChainID)
|
||||
|
||||
tmEndpoint := "/websocket"
|
||||
tmRPCAddr := cfg.RPC.ListenAddress
|
||||
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, &config, idxer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
shutdownCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancelFn()
|
||||
if err := httpSrv.Shutdown(shutdownCtx); err != nil {
|
||||
logger.Error("HTTP server shutdown produced a warning", "error", err.Error())
|
||||
} else {
|
||||
logger.Info("HTTP server shut down, waiting 5 sec")
|
||||
select {
|
||||
case <-time.Tick(5 * time.Second):
|
||||
case <-httpSrvDone:
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// At this point it is safe to block the process if we're in query only mode as
|
||||
// we do not need to start Rosetta or handle any Tendermint related processes.
|
||||
if gRPCOnly {
|
||||
// wait for signal capture and gracefully return
|
||||
return server.WaitForQuitSignals()
|
||||
}
|
||||
|
||||
var rosettaSrv crgserver.Server
|
||||
if config.Rosetta.Enable {
|
||||
offlineMode := config.Rosetta.Offline
|
||||
@ -496,68 +557,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
case <-time.After(types.ServerStartTime): // assume server started successfully
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
httpSrv *http.Server
|
||||
httpSrvDone chan struct{}
|
||||
)
|
||||
|
||||
if config.JSONRPC.Enable {
|
||||
genDoc, err := genDocProvider()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientCtx := clientCtx.WithChainID(genDoc.ChainID)
|
||||
|
||||
tmEndpoint := "/websocket"
|
||||
tmRPCAddr := cfg.RPC.ListenAddress
|
||||
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, &config, idxer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if tmNode.IsRunning() {
|
||||
_ = tmNode.Stop()
|
||||
}
|
||||
|
||||
if cpuProfileCleanup != nil {
|
||||
_ = cpuProfileCleanup()
|
||||
}
|
||||
|
||||
if apiSrv != nil {
|
||||
_ = apiSrv.Close()
|
||||
}
|
||||
|
||||
if grpcSrv != nil {
|
||||
grpcSrv.Stop()
|
||||
if grpcWebSrv != nil {
|
||||
if err := grpcWebSrv.Close(); err != nil {
|
||||
logger.Error("failed to close the grpcWebSrc", "error", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if httpSrv != nil {
|
||||
shutdownCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancelFn()
|
||||
|
||||
if err := httpSrv.Shutdown(shutdownCtx); err != nil {
|
||||
logger.Error("HTTP server shutdown produced a warning", "error", err.Error())
|
||||
} else {
|
||||
logger.Info("HTTP server shut down, waiting 5 sec")
|
||||
select {
|
||||
case <-time.Tick(5 * time.Second):
|
||||
case <-httpSrvDone:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("Bye!")
|
||||
}()
|
||||
|
||||
// Wait for SIGINT or SIGTERM signal
|
||||
return server.WaitForQuitSignals()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user