Skip to content

Refactor Relay initialization to use Static Factory Method pattern #4470

@konstantinabl

Description

@konstantinabl

Problem

The Relay class has a two-step initialization pattern (new Relay() + await relay.init()) that is error-prone and leads to services being initialized with undefined Redis client and not propery ensure operator has balance

Current flow:

  1. In server/index.ts we import relay from server/server.ts, which runs all the initialization code for the Relay class
  2. Services within the class initialize with undefined Redis client (CacheService, EthImpl)
  3. Later, init() connects Redis and sets this.redisClient
  4. But services already have undefined - updating the field doesn't help

Issues found:

  • Acceptance tests don't call relay.init() (discovered in PR review)
  • Services get undefined Redis client during construction
  • Easy to forget calling init() after construction
  • Split initialization logic between constructor and init() method

Proposed Solution

Implement the Static Factory Method pattern by:

  1. Make constructor private and accept redisClient parameter
  2. Create static async init(logger, register): Promise<Relay> method that:
    • Connects to Redis first, if redis is enable
    • Constructs Relay with connected Redis client
    • Performs operator balance check
    • Returns fully initialized instance

New usage:

// Old (error-prone)
const relay = new Relay(logger, register);
await relay.init();

// New (foolproof)
const relay = await Relay.init(logger, register);

Benefits

  • Enforces correct initialization - Private constructor prevents new Relay()
  • Services get working Redis client - Connected before construction
  • Single initialization method - All async setup in one place
  • Catches test bugs - Tests must use proper initialization
  • Type-safe - Returns Promise<Relay> with guarantees

Implementation Checklist

  • Update Relay class in packages/relay/src/lib/relay.ts
    • Make constructor private with redisClient parameter
    • Create static init() factory method
    • Move Redis connection logic into factory
    • Make isRedisEnabled() static
  • Update packages/server/src/index.ts to use Relay.init()
  • Update packages/ws-server/src/index.ts to use Relay.init()
  • Update acceptance tests in packages/server/tests/acceptance/
  • Update unit tests that instantiate Relay
  • Update documentation/examples

Breaking Change

This is a breaking change for any code that directly instantiates Relay with new Relay(). All consumers must update to use the async factory method.


Related: Addresses issue found in PR #4454 review

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestinternalFor changes that affect the project's internal workings but not its outward-facing functionality.

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions