Skip to content

Deliver events to handlers in every deployment (#327) - #339

Merged
Connor-Finn merged 1 commit into
mainfrom
tms/327-event-dispatch
Oct 4, 2026
Merged

Connor-Finn merged 1 commit into
mainfrom
tms/327-event-dispatch

Conversation

@Connor-Finn

Copy link
Copy Markdown
Collaborator

Closes #327.

What changed

  • Dispatch queue: PgBossEventBus used to fan events out only to handlers registered in its own process, so with DISABLE_EMBEDDED_WORKERS=true every event the API published was recorded and delivered nowhere. A process that runs no handlers now puts events on evt.__dispatch; every process that has started handlers consumes it and fans the events out to its own handler queues. pg-boss delivers each job once, so nothing is handled twice, including with several workers. This also covers WORKER_MODE=integrations.
  • Standalone worker: sets up the same DI container as the API (queue adapter, event bus, full command bus, delivery and arrival services) instead of hand-built command buses.
  • Handler registration: both processes register the event handlers with the full command bus, so the command-driven handlers (issue engine, auto-replenishment, route planning) run in either setup, whether or not an LLM is configured. Replaces the route-planning-only workaround from Plan a road route for custom-route shipments (#328) #336.

Behaviour change: in the default embedded dev setup, the issue engine and auto-replenishment now run (they were silently skipped before). The triage agent still needs an LLM provider.

Testing

  • New PgBossEventBus tests: dispatch from a non-consuming process, direct fan-out from a consuming one, fan-out of dispatched events, and no consuming with zero handlers.
  • Full backend suite (2,430), tsc, tenancy and boundary lints pass.
  • Live: API with DISABLE_EMBEDDED_WORKERS=true plus a WORKER_MODE=all worker. A shipment created through the API got its read-model row and timeline entry within ~2s, via the dispatch queue, and the worker ran route planning. In embedded mode, events still fan out directly, with no dispatch job and no duplicate timeline entry.

🤖 Generated with Claude Code

PgBossEventBus only fanned events out to handlers registered in its own
process, so with DISABLE_EMBEDDED_WORKERS=true every event the API
published was recorded and then delivered nowhere. A process that runs
no handlers now puts events on an evt.__dispatch queue, and every process
that has started handlers consumes it and fans them out to its handler
queues. This also covers WORKER_MODE=integrations workers.

The standalone worker now sets up the same DI container as the API
(queue adapter, event bus, full command bus, delivery and arrival
services) instead of hand-built command buses, and both processes
register the event handlers with the full command bus. The
command-driven handlers (issue engine, auto-replenishment, route
planning) therefore run in both setups, whether or not an LLM is
configured. Replaces the route-planning-only workaround from #336.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Connor-Finn
Connor-Finn merged commit 07a2a41 into main Oct 4, 2026
@Connor-Finn
Connor-Finn deleted the tms/327-event-dispatch branch October 4, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TMS: API with DISABLE_EMBEDDED_WORKERS=true delivers no domain events to any handler

1 participant