Skip to content

Feature: Add Outbox Event Relay and Handler Registry #153

Description

@3m1n3nc3

Description

The outbox delivered by #122 has a complete producer side — transactional writes, typed status, leasing, backoff, dead-letter, and versioned payload validation — but only one consumer. src/workers/wallet-provisioning.worker.ts is bound directly to WalletProvisioningOutboxHandler, so it drains only wallet provisioning work. event-schema.ts already registers UserCreated alongside the wallet events, and nothing consumes it: those rows are written inside the request transaction and then stay PENDING forever. Every new domain event today needs its own bespoke worker process.

Add a single relay that leases any pending outbox event and dispatches it by eventType to registered handlers, so domains subscribe to events instead of shipping a worker each.

File Location

learnault-api/src/lib/transactions/, learnault-api/src/jobs/, learnault-api/src/workers/, and learnault-api/docs/domains/REQUEST_AND_EVENT_FLOWS.md

Design Reference

API Roadmap Phase 1.1: Add Outbox Event Relay and Handler Registry. Consumes the primitives delivered by #122.

Dependencies

Tasks

  • Define a handler interface keyed by eventType and eventVersion
  • Add a registry that rejects duplicate registrations and unknown event types at startup
  • Build a relay that leases pending events, dispatches by type, and records each JobAttempt
  • Re-register the wallet provisioning handler through the registry and retire its bespoke worker
  • Add a UserCreated handler so the already-emitted event stops accumulating unconsumed
  • Mark events PUBLISHED only when every registered handler for that type succeeds
  • Route exhausted events to dead-letter and add an operator replay path
  • Document the subscribe-to-events flow for new domains

Acceptance Criteria

  • A new domain event needs a registered handler, not a new worker process
  • UserCreated events are consumed and no longer accumulate in PENDING
  • An event with no registered handler fails loudly at startup rather than silently stalling
  • A failing handler retries with backoff and dead-letters without blocking other event types
  • Replayed dead-letter events produce no duplicate side effects

Verification Evidence

  • Attach relay logs showing dispatch by type, a dead-lettered event, and a clean replay

Difficulty

Advanced

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions