github.com/koko1123/flow-go-1@v0.29.6/engine/access/state_stream/engine.go (about)

     1  package state_stream
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
     8  	access "github.com/onflow/flow/protobuf/go/flow/executiondata"
     9  	"github.com/rs/zerolog"
    10  	"google.golang.org/grpc"
    11  
    12  	"github.com/koko1123/flow-go-1/engine/common/rpc"
    13  	"github.com/koko1123/flow-go-1/model/flow"
    14  	"github.com/koko1123/flow-go-1/module/component"
    15  	"github.com/koko1123/flow-go-1/module/executiondatasync/execution_data"
    16  	"github.com/koko1123/flow-go-1/module/irrecoverable"
    17  	"github.com/koko1123/flow-go-1/storage"
    18  )
    19  
    20  // Config defines the configurable options for the ingress server.
    21  type Config struct {
    22  	ListenAddr              string
    23  	MaxExecutionDataMsgSize int  // in bytes
    24  	RpcMetricsEnabled       bool // enable GRPC metrics
    25  }
    26  
    27  // Engine exposes the server with the state stream API.
    28  // By default, this engine is not enabled.
    29  // In order to run this engine a port for the GRPC server to be served on should be specified in the run config.
    30  type Engine struct {
    31  	*component.ComponentManager
    32  	log     zerolog.Logger
    33  	backend *StateStreamBackend
    34  	server  *grpc.Server
    35  	config  Config
    36  	chain   flow.Chain
    37  	handler *Handler
    38  
    39  	stateStreamGrpcAddress net.Addr
    40  }
    41  
    42  // New returns a new ingress server.
    43  func NewEng(
    44  	config Config,
    45  	execDataStore execution_data.ExecutionDataStore,
    46  	headers storage.Headers,
    47  	seals storage.Seals,
    48  	results storage.ExecutionResults,
    49  	log zerolog.Logger,
    50  	chainID flow.ChainID,
    51  	apiRatelimits map[string]int, // the api rate limit (max calls per second) for each of the gRPC API e.g. Ping->100, GetExecutionDataByBlockID->300
    52  	apiBurstLimits map[string]int, // the api burst limit (max calls at the same time) for each of the gRPC API e.g. Ping->50, GetExecutionDataByBlockID->10
    53  ) *Engine {
    54  	// create a GRPC server to serve GRPC clients
    55  	grpcOpts := []grpc.ServerOption{
    56  		grpc.MaxRecvMsgSize(config.MaxExecutionDataMsgSize),
    57  		grpc.MaxSendMsgSize(config.MaxExecutionDataMsgSize),
    58  	}
    59  
    60  	var interceptors []grpc.UnaryServerInterceptor // ordered list of interceptors
    61  	// if rpc metrics is enabled, add the grpc metrics interceptor as a server option
    62  	if config.RpcMetricsEnabled {
    63  		interceptors = append(interceptors, grpc_prometheus.UnaryServerInterceptor)
    64  	}
    65  
    66  	if len(apiRatelimits) > 0 {
    67  		// create a rate limit interceptor
    68  		rateLimitInterceptor := rpc.NewRateLimiterInterceptor(log, apiRatelimits, apiBurstLimits).UnaryServerInterceptor
    69  		// append the rate limit interceptor to the list of interceptors
    70  		interceptors = append(interceptors, rateLimitInterceptor)
    71  	}
    72  
    73  	// add the logging interceptor, ensure it is innermost wrapper
    74  	interceptors = append(interceptors, rpc.LoggingInterceptor(log)...)
    75  
    76  	// create a chained unary interceptor
    77  	chainedInterceptors := grpc.ChainUnaryInterceptor(interceptors...)
    78  	grpcOpts = append(grpcOpts, chainedInterceptors)
    79  
    80  	server := grpc.NewServer(grpcOpts...)
    81  
    82  	backend := New(headers, seals, results, execDataStore)
    83  
    84  	e := &Engine{
    85  		log:     log.With().Str("engine", "state_stream_rpc").Logger(),
    86  		backend: backend,
    87  		server:  server,
    88  		chain:   chainID.Chain(),
    89  		config:  config,
    90  		handler: NewHandler(backend, chainID.Chain()),
    91  	}
    92  
    93  	e.ComponentManager = component.NewComponentManagerBuilder().
    94  		AddWorker(e.serve).
    95  		Build()
    96  	access.RegisterExecutionDataAPIServer(e.server, e.handler)
    97  
    98  	return e
    99  }
   100  
   101  // serve starts the gRPC server.
   102  // When this function returns, the server is considered ready.
   103  func (e *Engine) serve(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) {
   104  	e.log.Info().Str("state_stream_address", e.config.ListenAddr).Msg("starting grpc server on address")
   105  	l, err := net.Listen("tcp", e.config.ListenAddr)
   106  	if err != nil {
   107  		ctx.Throw(fmt.Errorf("error starting grpc server: %w", err))
   108  	}
   109  
   110  	e.stateStreamGrpcAddress = l.Addr()
   111  	e.log.Debug().Str("state_stream_address", e.stateStreamGrpcAddress.String()).Msg("listening on port")
   112  
   113  	go func() {
   114  		ready()
   115  		err = e.server.Serve(l)
   116  		if err != nil {
   117  			ctx.Throw(fmt.Errorf("error trying to serve grpc server: %w", err))
   118  		}
   119  	}()
   120  
   121  	<-ctx.Done()
   122  	e.server.GracefulStop()
   123  }