Skip to content

refactor: replace custom CQRS/Kafka/Outbox infrastructure with Wolverine - #97

Merged
falberthen merged 8 commits into
masterfrom
refactor/migrate-to-wolverine
Aug 29, 2026
Merged

refactor: replace custom CQRS/Kafka/Outbox infrastructure with Wolverine#97
falberthen merged 8 commits into
masterfrom
refactor/migrate-to-wolverine

Conversation

@falberthen

Copy link
Copy Markdown
Owner

Replaces the hand-rolled messaging and CQRS infrastructure with WolverineFx 6.30. Same team as Marten, so the durable inbox/outbox reuses the Marten event store directly, without Debezium and Kafka Connect or a polling worker. The move also turns OrderSaga into a real Wolverine saga and lets tracing lean on Wolverine's native handler spans instead of manual plumbing.

Before After
ICommandBus / IQueryBus + reflection dispatch Wolverine conventional handler discovery
Confluent.Kafka consumer/producer + KafkaBackgroundWorker Wolverine Kafka transport
Debezium + Kafka Connect CDC on mt_doc_outboxmessages Wolverine durable inbox/outbox (Marten-backed)
Manual saga state handling OrderSaga : Wolverine.Saga
ITraceable + TraceTaggingMiddleware + TelemetryTags Wolverine handler spans + [Audit] on the message OrderId

Reason

The previous custom stack duplicated what Wolverine does natively and carried real operational weight: a Debezium connector, a Kafka Connect container, a polling background worker, and bespoke tracing middleware. Wolverine gives the same guarantees (durable, exactly-once-ish delivery, retries, dead letter, etc) with less code and a supported upgrade path.

Key changes

  • Core loses CQRS/, EventBus/, Outbox/, Kafka/ abstractions. ICommand / IQuery survive as slim markers for CustomControllerBase overload resolution only. IntegrationEvent is now a pure marker.
  • Each service registers Wolverine via AddCoreInfrastructure; the three broker participants (Order/Payment/Shipment) configure UseKafka with durable inbox/outbox in their Program.cs.
  • Broker contracts carry [MessageIdentity(nameof(X))] so each bounded context's copy shares one wire name (and the name survives namespace moves).
  • Service clients: Kiota clients register through AddHttpClient<T>, which Wolverine 6's codegen can't inline. UseServiceClientServiceLocation() (new, in EcommerceDDD.ServiceClients) whitelists exactly those client types.
  • Observability: StronglyTypedId.ToString() added so [Audit] writes the bare id, so the SPA's Aspire deep-link (order.id) keeps working as before.

@falberthen
falberthen merged commit e7aa450 into master Aug 29, 2026
3 checks passed
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