Description
Currently, services communicate through the database using a polling strategy. Each service periodically queries tables looking for state changes (e.g., epochs in a specific status, new inputs). This approach has inherent latency equal to the polling interval and creates unnecessary load on the database.
This issue proposes implementing an internal library that enables event-driven communication between services using PostgreSQL's LISTEN/NOTIFY mechanism. This will reduce latency for state transitions and decrease database polling overhead.
Context
The system has 5 services (EvmReader, Advancer, Validator, Claimer, PRT) that currently poll the database for:
- Active applications
- Epochs in specific states (
OPEN, CLOSED, INPUTS_PROCESSED, CLAIM_CALCULATED, etc.)
- New inputs for processing
With LISTEN/NOTIFY, producers can notify consumers immediately when state changes occur, enabling near real-time reactions.
Design Considerations
-
Fire-and-forget nature: LISTEN/NOTIFY does not persist events. If a consumer is offline when an event is published, it will miss it. The library should be designed with this in mind, and consumers should implement a hybrid approach (events + periodic sync).
-
Interface-based design: Define clean interfaces (Publisher, Subscriber) to allow future alternative implementations (e.g., in-memory for single-process mode).
-
Channel strategy: Consider using per-app channels or event-type channels for efficient filtering.
Tasks
Proposed Event Types
const (
// Application events
EventAppRegistered EventType = "app.registered"
EventAppDeactivated EventType = "app.deactivated"
EventAppReactivated EventType = "app.reactivated"
EventAppInoperable EventType = "app.inoperable"
// Epoch events
EventEpochOpened EventType = "epoch.opened"
EventEpochClosed EventType = "epoch.closed"
EventEpochInputsProcessed EventType = "epoch.inputs_processed"
EventEpochClaimCalculated EventType = "epoch.claim_calculated"
EventEpochClaimSubmitted EventType = "epoch.claim_submitted"
EventEpochClaimAccepted EventType = "epoch.claim_accepted"
EventEpochClaimRejected EventType = "epoch.claim_rejected"
// Input events
EventInputReceived EventType = "input.received"
)
Acceptance Criteria
Notes
- This issue focuses only on the library implementation, not service migration
- Service migration will be handled in a separate follow-up issue
- The library should be designed to support future backends (e.g., in-memory) but only PostgreSQL needs to be implemented now
Description
Currently, services communicate through the database using a polling strategy. Each service periodically queries tables looking for state changes (e.g., epochs in a specific status, new inputs). This approach has inherent latency equal to the polling interval and creates unnecessary load on the database.
This issue proposes implementing an internal library that enables event-driven communication between services using PostgreSQL's
LISTEN/NOTIFYmechanism. This will reduce latency for state transitions and decrease database polling overhead.Context
The system has 5 services (EvmReader, Advancer, Validator, Claimer, PRT) that currently poll the database for:
OPEN,CLOSED,INPUTS_PROCESSED,CLAIM_CALCULATED, etc.)With
LISTEN/NOTIFY, producers can notify consumers immediately when state changes occur, enabling near real-time reactions.Design Considerations
Fire-and-forget nature:
LISTEN/NOTIFYdoes not persist events. If a consumer is offline when an event is published, it will miss it. The library should be designed with this in mind, and consumers should implement a hybrid approach (events + periodic sync).Interface-based design: Define clean interfaces (
Publisher,Subscriber) to allow future alternative implementations (e.g., in-memory for single-process mode).Channel strategy: Consider using per-app channels or event-type channels for efficient filtering.
Tasks
Define core interfaces in
internal/eventspackage:Eventstruct withType,AppID,Payload,TimestampEventTypeconstants for all domain eventsPublisherinterface withPublish(ctx, event)methodSubscriberinterface withSubscribe(ctx, filter)method returning event channelSubscriptionFilterstruct for filtering by event types and app IDsImplement PostgreSQL backend in
internal/events/postgres:pq.Listenerfor receiving notificationsImplement event publishing:
pg_notify()call on event publicationAdd unit tests:
Add integration tests:
Document the library:
Proposed Event Types
Acceptance Criteria
Notes