Skip to content

Commit 2baf5d5

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

File tree

3 files changed

+59
-10
lines changed

3 files changed

+59
-10
lines changed

bootstrap/bootstrap.go

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ import (
2020
"github.com/onflow/flow-go/module/util"
2121
"github.com/rs/zerolog"
2222
"github.com/sethvargo/go-limiter/memorystore"
23+
_ "google.golang.org/grpc"
2324
grpcOpts "google.golang.org/grpc"
2425
"google.golang.org/grpc/codes"
26+
"google.golang.org/grpc/resolver"
27+
"google.golang.org/grpc/resolver/manual"
2528
"google.golang.org/grpc/status"
2629

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