ADR-0001. In-process EventBus + BullMQ for eventing (no Kafka)
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-04-01 |
| Deciders | support-team |
| Supersedes | — |
Context
- Helpdesk needs to react to domain events (ticket created, status changed, assigned, message added) and run heavy work asynchronously (assignment, SLA monitoring, escalation, notifications, context enrichment, surveys).
- The platform standard for cross-service eventing is Kafka.
@platformatic/kafkais even declared inpackage.json. - However, all of helpdesk's event flows are intra-service: an event emitted by a use-case is consumed by a listener in the same service that fans out to background jobs. No other service subscribes to helpdesk events, and helpdesk subscribes to no external topics.
Decision
Use a two-tier in-service mechanism and no Kafka:
- In-process
EventBus(eventemitter3,EventBusComponent) — use-cases emitTicketEventTypesevents viaTicketEmitter; listeners insrc/application/events/listeners/handle them synchronously within the API process. Handler errors are caught and logged, never crashing the emitter. - BullMQ queues (
QueueComponent,WorkerComponent) — listeners fan out to durable Redis-backed queues; a separate worker process (RUN_MODE=worker) consumes them with per-queue retry/backoff.
@platformatic/kafka remains declared but unused (dead dependency).
Consequences
| Pros | Cons |
|---|---|
| No Kafka cluster dependency for a self-contained service | Events are not externally observable — other services cannot subscribe |
| Synchronous emit keeps HTTP responses fast (work deferred to BullMQ) | EventBus is at-most-once; a crash between emit and enqueue loses the fan-out |
| BullMQ gives durable retries + DLQ without a broker | Two delivery models (in-process + queue) to reason about |
| Simpler local dev (only Redis needed) | Dead @platformatic/kafka dep misleads readers and bloats install |
Alternatives Considered
| Option | Why rejected |
|---|---|
| Kafka for all eventing | Over-engineered for intra-service flows; adds broker dependency with no external subscriber |
| BullMQ only (no in-process bus) | Forces every domain reaction through Redis even when synchronous in-process handling suffices |
| Transactional outbox + CDC | Heavy for a service with no external event consumers |
References
src/components/event-bus/event-bus.ts(eventemitter3)src/components/event-bus/event-registry.tssrc/application/events/emitters/ticket.emitter.tssrc/components/queue.component.tspackage.json(@platformatic/kafkadeclared, unused)