Skip to content

Commit b19f0dc

Browse files
alexanderbezyihuang
authored andcommitted
refactor: cleanup server logic (backport #15041)
cleanup for easier review
1 parent 329d7d8 commit b19f0dc

File tree

15 files changed

+267
-191
lines changed

15 files changed

+267
-191
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
4848
* (x/staking) [#16068](https://github.com/cosmos/cosmos-sdk/pull/16068) Update simulation to allow non-EOA accounts to stake.
4949
* (server) [#16142](https://github.com/cosmos/cosmos-sdk/pull/16142) Remove JSON Indentation from the GRPC to REST gateway's responses. (Saving bandwidth)
5050
* (types) [#16145](https://github.com/cosmos/cosmos-sdk/pull/16145) Rename interface `ExtensionOptionI` back to `TxExtensionOptionI` to avoid breaking change.
51+
* (server) [#15041](https://github.com/cosmos/cosmos-sdk/pull/15041) Remove unnecessary sleeps from gRPC and API server initiation. The servers will start and accept requests as soon as they're ready.
5152

5253
### Bug Fixes
5354

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ require (
5656
github.com/tendermint/go-amino v0.16.0
5757
github.com/tidwall/btree v1.6.0
5858
golang.org/x/crypto v0.7.0
59-
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc
59+
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
60+
golang.org/x/sync v0.1.0
6061
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4
6162
google.golang.org/grpc v1.55.0
6263
google.golang.org/protobuf v1.30.0

go.sum

+3-2
Original file line numberDiff line numberDiff line change
@@ -1025,8 +1025,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
10251025
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
10261026
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
10271027
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
1028-
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
1029-
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
1028+
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 h1:LGJsf5LRplCck6jUCH3dBL2dmycNruWNF5xugkSlfXw=
1029+
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
10301030
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
10311031
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
10321032
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1160,6 +1160,7 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ
11601160
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
11611161
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
11621162
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
1163+
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
11631164
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
11641165
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
11651166
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

server/api/server.go

+36-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package api
22

33
import (
4+
"context"
45
"fmt"
56
"net"
67
"net/http"
@@ -47,6 +48,7 @@ func CustomGRPCHeaderMatcher(key string) (string, bool) {
4748
switch strings.ToLower(key) {
4849
case grpctypes.GRPCBlockHeightHeader:
4950
return grpctypes.GRPCBlockHeightHeader, true
51+
5052
default:
5153
return runtime.DefaultHeaderMatcher(key)
5254
}
@@ -83,9 +85,12 @@ func New(clientCtx client.Context, logger log.Logger) *Server {
8385

8486
// Start starts the API server. Internally, the API server leverages Tendermint's
8587
// JSON RPC server. Configuration options are provided via config.APIConfig
86-
// and are delegated to the Tendermint JSON RPC server. The process is
87-
// non-blocking, so an external signal handler must be used.
88-
func (s *Server) Start(cfg config.Config) error {
88+
// and are delegated to the Tendermint JSON RPC server.
89+
//
90+
// Note, this creates a blocking process if the server is started successfully.
91+
// Otherwise, an error is returned. The caller is expected to provide a Context
92+
// that is properly canceled or closed to indicate the server should be stopped.
93+
func (s *Server) Start(ctx context.Context, cfg config.Config) error {
8994
s.mtx.Lock()
9095

9196
tmCfg := tmrpcserver.DefaultConfig()
@@ -102,17 +107,38 @@ func (s *Server) Start(cfg config.Config) error {
102107

103108
s.registerGRPCGatewayRoutes()
104109
s.listener = listener
105-
var h http.Handler = s.Router
106110

107111
s.mtx.Unlock()
108112

109-
if cfg.API.EnableUnsafeCORS {
110-
allowAllCORS := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))
111-
return tmrpcserver.Serve(s.listener, allowAllCORS(h), s.logger, tmCfg)
112-
}
113+
errCh := make(chan error)
114+
115+
// Start the API in an external goroutine as Serve is blocking and will return
116+
// an error upon failure, which we'll send on the error channel that will be
117+
// consumed by the for block below.
118+
go func(enableUnsafeCORS bool) {
119+
s.logger.Info("starting API server...", "address", cfg.API.Address)
113120

114-
s.logger.Info("starting API server...")
115-
return tmrpcserver.Serve(s.listener, s.Router, s.logger, tmCfg)
121+
if enableUnsafeCORS {
122+
allowAllCORS := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))
123+
errCh <- tmrpcserver.Serve(s.listener, allowAllCORS(s.Router), s.logger, tmCfg)
124+
} else {
125+
errCh <- tmrpcserver.Serve(s.listener, s.Router, s.logger, tmCfg)
126+
}
127+
}(cfg.API.EnableUnsafeCORS)
128+
129+
// Start a blocking select to wait for an indication to stop the server or that
130+
// the server failed to start properly.
131+
select {
132+
case <-ctx.Done():
133+
// The calling process cancelled or closed the provided context, so we must
134+
// gracefully stop the API server.
135+
s.logger.Info("stopping API server...", "address", cfg.API.Address)
136+
return s.Close()
137+
138+
case err := <-errCh:
139+
s.logger.Error("failed to start API server", "err", err)
140+
return err
141+
}
116142
}
117143

118144
// Close closes the API server.

server/grpc/grpc_web.go

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
package grpc
22

33
import (
4+
"context"
45
"fmt"
56
"net/http"
67
"time"
78

9+
"github.com/cometbft/cometbft/libs/log"
810
"github.com/improbable-eng/grpc-web/go/grpcweb"
911
"google.golang.org/grpc"
1012

1113
"github.com/cosmos/cosmos-sdk/server/config"
12-
"github.com/cosmos/cosmos-sdk/server/types"
1314
)
1415

1516
// StartGRPCWeb starts a gRPC-Web server on the given address.
16-
func StartGRPCWeb(grpcSrv *grpc.Server, config config.Config) (*http.Server, error) {
17+
func StartGRPCWeb(ctx context.Context, logger log.Logger, grpcSrv *grpc.Server, config config.Config) error {
1718
var options []grpcweb.Option
1819
if config.GRPCWeb.EnableUnsafeCORS {
1920
options = append(options,
@@ -32,15 +33,24 @@ func StartGRPCWeb(grpcSrv *grpc.Server, config config.Config) (*http.Server, err
3233

3334
errCh := make(chan error)
3435
go func() {
36+
logger.Info("starting gRPC web server...", "address", config.GRPCWeb.Address)
3537
if err := grpcWebSrv.ListenAndServe(); err != nil {
3638
errCh <- fmt.Errorf("[grpc] failed to serve: %w", err)
3739
}
3840
}()
3941

42+
// Start a blocking select to wait for an indication to stop the server or that
43+
// the server failed to start properly.
4044
select {
45+
case <-ctx.Done():
46+
// The calling process cancelled or closed the provided context, so we must
47+
// gracefully stop the gRPC-web server.
48+
logger.Info("stopping gRPC web server...", "address", config.GRPCWeb.Address)
49+
grpcWebSrv.Close()
50+
return nil
51+
4152
case err := <-errCh:
42-
return nil, err
43-
case <-time.After(types.ServerStartTime): // assume server started successfully
44-
return grpcWebSrv, nil
53+
logger.Error("failed to start gRPC Web server", "err", err)
54+
return err
4555
}
4656
}

server/grpc/server.go

+35-14
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package grpc
22

33
import (
4+
"context"
45
"fmt"
56
"net"
6-
"time"
77

8+
"github.com/cometbft/cometbft/libs/log"
89
"google.golang.org/grpc"
910

1011
"github.com/cosmos/cosmos-sdk/client"
@@ -17,8 +18,9 @@ import (
1718
_ "github.com/cosmos/cosmos-sdk/types/tx/amino" // Import amino.proto file for reflection
1819
)
1920

20-
// StartGRPCServer starts a gRPC server on the given address.
21-
func StartGRPCServer(clientCtx client.Context, app types.Application, cfg config.GRPCConfig) (*grpc.Server, error) {
21+
// NewGRPCServer returns a correctly configured and initialized gRPC server.
22+
// Note, the caller is responsible for starting the server. See StartGRPCServer.
23+
func NewGRPCServer(clientCtx client.Context, app types.Application, cfg config.GRPCConfig) (*grpc.Server, error) {
2224
maxSendMsgSize := cfg.MaxSendMsgSize
2325
if maxSendMsgSize == 0 {
2426
maxSendMsgSize = config.DefaultGRPCMaxSendMsgSize
@@ -46,39 +48,58 @@ func StartGRPCServer(clientCtx client.Context, app types.Application, cfg config
4648
for _, m := range clientCtx.TxConfig.SignModeHandler().Modes() {
4749
modes[m.String()] = (int32)(m)
4850
}
51+
4952
return modes
5053
}(),
5154
ChainID: clientCtx.ChainID,
5255
SdkConfig: sdk.GetConfig(),
5356
InterfaceRegistry: clientCtx.InterfaceRegistry,
5457
})
5558
if err != nil {
56-
return nil, err
59+
return nil, fmt.Errorf("failed to register reflection service: %w", err)
5760
}
5861

5962
// Reflection allows external clients to see what services and methods
6063
// the gRPC server exposes.
6164
gogoreflection.Register(grpcSrv)
6265

66+
return grpcSrv, nil
67+
}
68+
69+
// StartGRPCServer starts the provided gRPC server on the address specified in cfg.
70+
//
71+
// Note, this creates a blocking process if the server is started successfully.
72+
// Otherwise, an error is returned. The caller is expected to provide a Context
73+
// that is properly canceled or closed to indicate the server should be stopped.
74+
func StartGRPCServer(ctx context.Context, logger log.Logger, cfg config.GRPCConfig, grpcSrv *grpc.Server) error {
6375
listener, err := net.Listen("tcp", cfg.Address)
6476
if err != nil {
65-
return nil, err
77+
return fmt.Errorf("failed to listen on address %s: %w", cfg.Address, err)
6678
}
6779

6880
errCh := make(chan error)
81+
82+
// Start the gRPC in an external goroutine as Serve is blocking and will return
83+
// an error upon failure, which we'll send on the error channel that will be
84+
// consumed by the for block below.
6985
go func() {
70-
err = grpcSrv.Serve(listener)
71-
if err != nil {
72-
errCh <- fmt.Errorf("failed to serve: %w", err)
73-
}
86+
logger.Info("starting gRPC server...", "address", cfg.Address)
87+
errCh <- grpcSrv.Serve(listener)
7488
}()
7589

90+
// Start a blocking select to wait for an indication to stop the server or that
91+
// the server failed to start properly.
7692
select {
77-
case err := <-errCh:
78-
return nil, err
93+
case <-ctx.Done():
94+
// The calling process cancelled or closed the provided context, so we must
95+
// gracefully stop the gRPC server.
96+
logger.Info("stopping gRPC server...", "address", cfg.Address)
97+
grpcSrv.GracefulStop()
98+
99+
return nil
79100

80-
case <-time.After(types.ServerStartTime):
81-
// assume server started successfully
82-
return grpcSrv, nil
101+
case err := <-errCh:
102+
logger.Error("failed to start gRPC server", "err", err)
103+
return err
83104
}
84105
}

0 commit comments

Comments
 (0)