Plan — AW-7: Create EventBusService abstraction backed by Redis#
Summary#
Create a @Global() EventBusModule with EventBusService that wraps Redis pub/sub for typed, cross-process event delivery. Uses the existing ioredis dependency and REDIS_HOST/REDIS_PORT/REDIS_DB config. Runs alongside EventEmitter2 — no existing code is changed.
Files#
| File | Action | Description |
|---|---|---|
src/event-bus/event-bus.events.ts | create | Typed event map: event name → payload interface for all 6 events |
src/event-bus/event-bus.service.ts | create | EventBusService — pub/sub client, emit(), on(), onModuleDestroy() |
src/event-bus/event-bus.module.ts | create | @Global() module: provides two ioredis clients (pub + sub), exports service |
src/event-bus/index.ts | create | Barrel export |
src/event-bus/event-bus.service.spec.ts | create | Unit tests: emit → Redis publish, handler invocation, multi-handler, error isolation |
src/app.module.ts | modify | Import EventBusModule |
Steps#
- Define typed event map — Create
event-bus.events.tswithEventMapinterface mapping each event name (task.updated,task.stuck,job.created,job.completed,job.failed,artefacts.synced) to its payload type. Derive payload shapes from current emit sites intask-state.service.ts,watchdog.service.ts,sqlite-job-queue.ts,phase-router.service.ts. - Implement EventBusService — Create service with two ioredis clients (
pubfor publishing,subfor subscribing). Channel prefix:agentsde:events:.emit<K>(event, payload)serializes to JSON and publishes onpubclient; catches errors, logs, and swallows.on<K>(event, handler)subscribes onsubclient and dispatches to registered handlers. Multiple handlers per event supported. Handler errors caught individually.onModuleDestroy()quits both clients. - Create EventBusModule —
@Global()NestJS module. Factory-provides two ioredis clients fromConfigService(REDIS_HOST,REDIS_PORT,REDIS_DB). Follow the pattern insrc/health/health.module.ts. ExportEventBusService. - Register in AppModule — Add
EventBusModuletoimportsinsrc/app.module.ts. - Write unit tests — Test cases: (a)
emit()callspub.publish()with correct channel and serialized payload, (b)on()handler receives deserialized payload on message, (c) multiple handlers all invoked, (d) error in one handler does not prevent others, (e)emit()swallows Redis errors and logs, (f)onModuleDestroy()quits both clients. - Build and lint verification — Run
npm run buildandnpm run lintto confirm zero errors.
Verification#
npm run buildpasses without errorsnpm run testpasses — all new and existing tests greennpm run lintpasses with zero warnings
Risks#
- Redis unavailability during emit: Mitigated by design —
emit()catches all errors and logs without throwing. Pipeline advancement is driven by the job queue, not events. - Channel naming collision: Prefix
agentsde:events:scopes channels to this application; documented in the event map.