Skip to content

Commit b9c76eb

Browse files
committed
Allow adding back-up AN hosts to be used for client-side request load balancing
1 parent 039545d commit b9c76eb

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

bootstrap/bootstrap.go

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
"github.com/sethvargo/go-limiter/memorystore"
2323
grpcOpts "google.golang.org/grpc"
2424
"google.golang.org/grpc/codes"
25+
"google.golang.org/grpc/resolver"
26+
"google.golang.org/grpc/resolver/manual"
2527
"google.golang.org/grpc/status"
2628

2729
"github.com/onflow/flow-evm-gateway/api"
@@ -482,16 +484,53 @@ func StartEngine(
482484
// setupCrossSporkClient sets up a cross-spork AN client.
483485
func setupCrossSporkClient(config config.Config, logger zerolog.Logger) (*requester.CrossSporkClient, error) {
484486
// create access client with cross-spork capabilities
485-
currentSporkClient, err := grpc.NewClient(
486-
config.AccessNodeHost,
487-
grpc.WithGRPCDialOptions(
488-
grpcOpts.WithDefaultCallOptions(grpcOpts.MaxCallRecvMsgSize(DefaultMaxMessageSize)),
489-
grpcOpts.WithUnaryInterceptor(retryInterceptor(
490-
DefaultResourceExhaustedMaxRetryDelay,
491-
DefaultResourceExhaustedRetryDelay,
492-
)),
493-
),
494-
)
487+
var currentSporkClient *grpc.Client
488+
var err error
489+
490+
if len(config.AccessNodeBackupHosts) > 0 {
491+
mr := manual.NewBuilderWithScheme("dns")
492+
defer mr.Close()
493+
494+
json := `{"loadBalancingConfig": [{"pick_first":{}}]}`
495+
endpoints := []resolver.Endpoint{
496+
{Addresses: []resolver.Address{{Addr: config.AccessNodeHost}}},
497+
}
498+
499+
for _, accessNodeBackupAddr := range config.AccessNodeBackupHosts {
500+
endpoints = append(endpoints, resolver.Endpoint{
501+
Addresses: []resolver.Address{{Addr: accessNodeBackupAddr}},
502+
})
503+
}
504+
505+
mr.InitialState(resolver.State{
506+
Endpoints: endpoints,
507+
})
508+
509+
currentSporkClient, err = grpc.NewClient(
510+
mr.Scheme(),
511+
grpc.WithGRPCDialOptions(
512+
grpcOpts.WithDefaultCallOptions(grpcOpts.MaxCallRecvMsgSize(DefaultMaxMessageSize)),
513+
grpcOpts.WithResolvers(mr),
514+
grpcOpts.WithDefaultServiceConfig(json),
515+
grpcOpts.WithUnaryInterceptor(retryInterceptor(
516+
DefaultResourceExhaustedMaxRetryDelay,
517+
DefaultResourceExhaustedRetryDelay,
518+
)),
519+
),
520+
)
521+
} else {
522+
currentSporkClient, err = grpc.NewClient(
523+
config.AccessNodeHost,
524+
grpc.WithGRPCDialOptions(
525+
grpcOpts.WithDefaultCallOptions(grpcOpts.MaxCallRecvMsgSize(DefaultMaxMessageSize)),
526+
grpcOpts.WithUnaryInterceptor(retryInterceptor(
527+
DefaultResourceExhaustedMaxRetryDelay,
528+
DefaultResourceExhaustedRetryDelay,
529+
)),
530+
),
531+
)
532+
}
533+
495534
if err != nil {
496535
return nil, fmt.Errorf(
497536
"failed to create client connection for host: %s, with error: %w",

cmd/run/cmd.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ func parseConfigFromFlags() error {
201201
}
202202
cfg.FilterExpiry = exp
203203

204+
if accessBackupHosts != "" {
205+
cfg.AccessNodeBackupHosts = strings.Split(accessBackupHosts, ",")
206+
}
207+
204208
if accessSporkHosts != "" {
205209
heightHosts := strings.Split(accessSporkHosts, ",")
206210
cfg.AccessNodePreviousSporkHosts = append(cfg.AccessNodePreviousSporkHosts, heightHosts...)
@@ -242,6 +246,7 @@ var (
242246
logWriter,
243247
filterExpiry,
244248
accessSporkHosts,
249+
accessBackupHosts,
245250
cloudKMSKey,
246251
cloudKMSProjectID,
247252
cloudKMSLocationID,
@@ -259,6 +264,7 @@ func init() {
259264
Cmd.Flags().IntVar(&cfg.RPCPort, "rpc-port", 8545, "Port for the RPC API server")
260265
Cmd.Flags().BoolVar(&cfg.WSEnabled, "ws-enabled", false, "Enable websocket connections")
261266
Cmd.Flags().StringVar(&cfg.AccessNodeHost, "access-node-grpc-host", "localhost:3569", "Host to the flow access node gRPC API")
267+
Cmd.Flags().StringVar(&accessBackupHosts, "access-node-backup-hosts", "", `Backup AN hosts to use in case of connectivity issues, defined following the schema: {host1},{host2} as a comma separated list (e.g. "host-1.com,host2.com")`)
262268
Cmd.Flags().StringVar(&accessSporkHosts, "access-node-spork-hosts", "", `Previous spork AN hosts, defined following the schema: {host1},{host2} as a comma separated list (e.g. "host-1.com,host2.com")`)
263269
Cmd.Flags().StringVar(&flowNetwork, "flow-network-id", "flow-emulator", "Flow network ID (flow-emulator, flow-previewnet, flow-testnet, flow-mainnet)")
264270
Cmd.Flags().StringVar(&coinbase, "coinbase", "", "Coinbase address to use for fee collection")

config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ type Config struct {
4545
DatabaseDir string
4646
// AccessNodeHost defines the current spork Flow network AN host.
4747
AccessNodeHost string
48+
// AccessNodeBackupHosts contains a list of ANs hosts to use as backup, in
49+
// case of connectivity issues with `AccessNodeHost`.
50+
AccessNodeBackupHosts []string
4851
// AccessNodePreviousSporkHosts contains a list of the ANs hosts for each spork
4952
AccessNodePreviousSporkHosts []string
5053
// GRPCPort for the RPC API server

0 commit comments

Comments
 (0)