Skip to content

feat: Wire event dispatcher for ctx.events.dispatch#157

Merged
doubleailes merged 1 commit into
mainfrom
feat/event-dispatcher
Apr 29, 2026
Merged

feat: Wire event dispatcher for ctx.events.dispatch#157
doubleailes merged 1 commit into
mainfrom
feat/event-dispatcher

Conversation

@doubleailes
Copy link
Copy Markdown
Owner

Summary

Closes the third and final piece of the async-handler refactor — events.

  • New girolle/src/events.rsEventDispatcherCore owns a publish channel and a DashSet<String> cache of declared {source}.events topic exchanges (durable: true). Exchanges are declared lazily the first time a given source emits, so a single dispatcher can fan out events for multiple sources.
  • EventDispatcher now holds Option<Arc<EventDispatcherCore>> plus the parent delivery's FieldTable. pub async fn dispatch<T: Serialize>(source_service, event_type, &payload) serializes the payload to JSON and publishes with persistent delivery, JSON content-type, and event_type as the routing key. nameko.AMQP_URI is stamped onto headers and the parent's nameko.call_id_stack (when present) is propagated through.
  • RpcService startup calls EventDispatcherCore::new(&conn, conf, id) once and wires the resulting dispatcher into SharedData. Per delivery the consumer does with_parent_headers(inbound_headers.clone()) for both rpc and events.
  • examples/src/event_emitter.rs — a service that emits a user_created event on users.events from inside a handler.

Acceptance

With this merged, a handler can:

  • Receive an RpcContext carrying inbound metadata
  • Call other services via ctx.rpc.call(...)
  • Emit Nameko-compatible events via ctx.events.dispatch(...)

…which closes out the original async-handler issue's acceptance criteria.

Known limitations (deferred)

  • No publisher confirms — dispatch returns once the publish has been handed to the broker, no broker-side ack.
  • Outbound call_id_stack propagated as-is from the parent (matches the RPC caller's behavior; see feat: Wire in-service RPC core for ctx.rpc.call #156).
  • No event consumer support yet — that's a separate piece of work.

Test plan

  • `cargo build --workspace`
  • `cargo build --examples` (incl. new `event_emitter`)
  • `cargo test --workspace --lib` (14 passed)
  • `cargo test --workspace --doc` (30 + 1 passed)
  • `cargo clippy --workspace --all-targets`
  • Smoke test: run `event_emitter`, call `users.create_user`, observe a message on `users.events` with routing key `user_created` (e.g. via the RabbitMQ management UI or a Nameko subscriber).

🤖 Generated with Claude Code

Add a real implementation behind the placeholder `EventDispatcher`
introduced earlier. Each `RpcService` now stands up a per-instance
event dispatcher core: a publish channel and a `DashSet` of declared
`{source}.events` topic exchanges. Exchanges are declared lazily the
first time a given source emits.

`EventDispatcher::dispatch<T: Serialize>(source, event_type, &payload)`
is `pub async`. Per delivery, the consumer derives a dispatcher
stamped with the inbound delivery's headers via `with_parent_headers`,
so `nameko.call_id_stack` propagates through to emitted events.
`nameko.AMQP_URI` is always stamped. Messages use durable delivery
(mode 2), JSON content-type, and the routing key is the event type.

The new `examples/src/event_emitter.rs` demonstrates a service that
emits `user_created` on the `users.events` exchange.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@doubleailes doubleailes merged commit 2b2c393 into main Apr 29, 2026
5 checks passed
@doubleailes doubleailes deleted the feat/event-dispatcher branch April 29, 2026 11:14
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.

1 participant