Skip to content

[utils] Extract gRPC service lifecycle from utils/connection into utils/grpcservice #507

@cendhu

Description

@cendhu

Problem

The utils/connection package currently owns two unrelated responsibilities:

  1. Networking primitives — ServerConfig, TLSConfig, GrpcServer(), Listener(), client connections, credentials, rate limiting.
  2. Service lifecycle orchestration — Service interface (Run, WaitForReady, RegisterService), StartService, RunGrpcServer.

These should be separated because:

  • Service is not a connection concept. Run starts application logic (DB pools, block delivery, verifier managers). WaitForReady gates initialization. Neither relates to networking or gRPC transport. They ended up in connection because StartService wires services to gRPC servers, but the wiring is a consumer of connection primitives, not a primitive itself.
  • RunGrpcServer does too much. It creates the listener, creates the server, accepts a registration callback, and serves — all in one function. This conflates server creation (a connection concern) with service registration and lifecycle (an orchestration concern). The registration callback (register func(server *grpc.Server)) exists because RunGrpcServer owns the server internally instead of letting the caller create and configure it first.
  • Harder to navigate. When reading utils/connection, you expect networking configuration and transport credentials. Finding service lifecycle orchestration there is surprising. New contributors have to understand the package does two things.

Suggested approach

Create utils/grpcservice and move the service lifecycle code there:

utils/grpcservice:

  • Registerer interface — RegisterService(server *grpc.Server) — for services that register on a gRPC server.
  • Service interface — embeds Registerer, adds Run(ctx) error and WaitForReady(ctx) bool — for full lifecycle services.
  • Serve(ctx, service Registerer, serverConfig) — creates server and listener from config, registers the service, serves until context done. For simple services (e.g., mocks) without lifecycle.
  • StartAndServe(ctx, service Service, serverConfigs...) — full lifecycle: runs the service, waits for ready, then calls Serve for each server config.

utils/connection keeps only:

  • ServerConfig, TLSConfig, TLSMaterials
  • ServerConfig.GrpcServer() — creates a configured *grpc.Server
  • ServerConfig.Listener(ctx) — creates a net.Listener
  • Client connections, credentials, rate limiting, keep-alive

Dependency direction: utils/grpcserviceutils/connection. One-way, no cycles.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions