Wolverine is a .NET mediator + message bus that unifies local command execution, asynchronous messaging, and durable event workflows behind the same API surface (IMessageBus/IMessageContext).12 Its event system is built around endpoint abstractions (listener/sender), subscription-based routing, and pluggable transports (local queues, built-in TCP, plus broker adapters) that all operate on a normalized Envelope model.345 Reliability is centered on transactional inbox/outbox patterns, durable message stores, replay/recovery agents, and configurable deduplication windows for idempotency.678 Long-running orchestration is implemented with stateful sagas (Saga base type) and persistence integration, including optimistic concurrency semantics via saga versioning.910
Wolverine’s runtime composes message handling, routing, and durability into a single hosted runtime (WolverineRuntime) with telemetry, message tracking, scheduled processing, and endpoint management.11 Handler execution is code-generated at bootstrapping time (not reflection-based at runtime), then driven through a pipeline that deserializes envelopes, handles expiration and responses, and dispatches to typed executors.1213
┌─────────────────────────────── App Code ───────────────────────────────┐
│ IMessageBus / IMessageContext │
│ - InvokeAsync / SendAsync / PublishAsync / ScheduleAsync │
└───────────────┬──────────────────────────────────────────────────────────┘
│ creates/uses Envelope + DeliveryOptions
▼
┌────────────────────────── Wolverine Runtime ─────────────────────────────┐
│ Routing (subscriptions/conventions) ──► Endpoint selection │
│ HandlerPipeline ─► Deserialize ─► Executor ─► Continuations │
│ Telemetry + Metrics + Reply tracking + Scheduled jobs │
└───────┬───────────────────────────────┬──────────────────────────────────┘
│ │
▼ ▼
┌─────────────── Transports ───────────────┐ ┌────── Durable Storage ──────┐
│ Local queues / TCP / external adapters │ │ Inbox / Outbox / Deadletters│
│ (IListener/ISender/ITransport) │ │ Recovery + reassignment │
└───────────────────────────────────────────┘ └─────────────────────────────┘
The primary API contract exposes synchronous-style invoke (InvokeAsync), asynchronous fan-out (SendAsync/PublishAsync), endpoint-targeted sends, topic broadcast, and scheduling extensions through one interface family.1 The docs explicitly describe IMessageBus as the main entry point and distinguish SendAsync() vs PublishAsync() by subscriber enforcement behavior.2 Wolverine also supports tenant-scoped invocations and endpoint resolution by name/URI, which is important for modular monolith or multi-transport topologies.1
Routing is subscription-driven: on first use per message type, Wolverine resolves forwarding rules, explicit rules, local-conventional routing, then transport conventions.4 Endpoint behavior is a first-class runtime concept with mode controls (Durable, BufferedInMemory, Inline), listener scope (CompetingConsumers, Exclusive, PinnedToLeader), and parallelism/sharding options.3 Transport internals are standardized around ITransport, Endpoint, IListener, and ISender, allowing local queueing and TCP to share the same envelope semantics as broker adapters.5 Local transport is TPL Dataflow-based with queue-level durability/concurrency controls, while TCP provides a lightweight built-in network transport for direct inter-process messaging.1415
WolverineRuntime owns endpoint collection, handler graph, pooled message contexts, reply tracking, and telemetry meters, and it wires these as an IHostedService runtime substrate.11 HandlerPipeline performs cancellation gating, envelope deserialization, unknown-message fallback, expiry discard, response completion, and execution via typed executors.13 This design keeps “event system” semantics consistent whether messages originate locally, from scheduled jobs, or from external listeners.1113
The durability docs define Wolverine’s transactional outbox/inbox as the core mechanism for store-and-forward reliability and eventual consistency without distributed transactions.6 Runtime durability options include mode (Solo, Balanced, Serverless, MediatorOnly), stale inbox/outbox recovery thresholds, deduplication retention window, and node reassignment polling.7 On the sending side, DurableSendingAgent persists outgoing envelopes, retries with bounded retry-queue storage, discards expired items, and reassigns overflow/stale work for later processing.8 Idempotent delivery is explicitly tied to durable inbox usage, with default “keep handled message” retention used for duplicate suppression.167
Wolverine documents sagas as stateful, long-running process managers: saga state type + correlated messages + persistence strategy + identity.9 The Saga base class provides completion semantics (MarkCompleted) and version field support for optimistic concurrency-aware providers.10 Docs also show scheduling/timeouts as native saga patterns and caution about invoking directly back into the same saga via InvokeAsync, favoring cascading messages.9
Wolverine emphasizes zero runtime reflection in execution: reflection is used for discovery/bootstrap, then generated runtime wrappers execute handlers.12 Handler conventions support plain public methods/classes (including cascading return values and injected dependencies), making event handlers idiomatic C# methods rather than framework-heavy interfaces.12 This is a key differentiator versus conventional mediator libraries and explains why routing + codegen are central to startup behavior.124
A typical durable event flow is: app code calls SendAsync/PublishAsync → routing selects endpoints/subscriptions → sender writes envelope to outbox (if durable mode) → transport delivery → listener persists to inbox (if durable) → HandlerPipeline deserializes and executes → success marks/deletes or retains handled records for dedupe window.14681316 For local-only flows, the same API can enqueue to in-process queues with optional durability and scheduling; for remote flows, the same API can target TCP or broker endpoints.14152
Durability settings are explicitly tuned for deployment style: Solo accelerates single-node recovery behavior, Balanced assumes multi-node assignment/reassignment, while Serverless and MediatorOnly disable persistence-centric behavior for lightweight execution contexts.7 Endpoint listener auto-start behavior is also mode-sensitive (e.g., CompetingConsumers in balanced mode), which impacts rollout topology in clustered deployments.3 Metrics/tracing are built into runtime initialization through meter/counters and optional endpoint telemetry, supporting observability of sent/executed/failed/dead-lettered traffic.113
| Repository | Purpose | Key Files |
|---|---|---|
| JasperFx/wolverine | Core mediator/message bus runtime and transports | src/Wolverine/IMessageBus.cs, src/Wolverine/Runtime/HandlerPipeline.cs, src/Wolverine/Configuration/Endpoint.cs |
| JasperFx/wolverine | Durability, inbox/outbox, recovery agents | src/Wolverine/DurabilitySettings.cs, src/Wolverine/Persistence/Durability/DurableSendingAgent.cs, docs/guide/durability/index.md |
| JasperFx/wolverine | Saga/process-manager model | src/Wolverine/Saga.cs, docs/guide/durability/sagas.md |
| JasperFx/wolverine | Messaging usage and transport guidance | docs/guide/messaging/message-bus.md, docs/guide/messaging/subscriptions.md, docs/guide/messaging/transports/*.md |
High confidence: Core architecture, runtime flow, durability mechanics, routing precedence, and saga model are all directly verified in official source and docs from the Wolverine repository at commit 055ec9e611d37dae8e53404d8e57c35165b0d96d.136101113
Medium confidence: Operational guidance about “used in practice” (e.g., when to pick certain modes) is inferred from documented intent/comments and option semantics rather than production benchmark data in the referenced files.715
Known gap: This report focuses on the core repo and not every transport adapter implementation package in depth (RabbitMQ, Kafka, etc.), though the abstraction model and transport docs are covered.5
Footnotes
-
src/Wolverine/IMessageBus.cs:3-44,47-58,100-192(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 ↩5 -
docs/guide/messaging/message-bus.md:1-58,66-76,98-109(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 -
src/Wolverine/Configuration/Endpoint.cs:54-75,90-109,166-197,214-240(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 ↩5 -
docs/guide/messaging/subscriptions.md:1-4,21-35,93-109(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 -
docs/guide/messaging/transports/index.md:7-22(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 -
docs/guide/durability/index.md:8-16,17-22,76-84,196-203(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 -
src/Wolverine/DurabilitySettings.cs:6-34,39-52,86-124,133-160(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 ↩5 -
src/Wolverine/Persistence/Durability/DurableSendingAgent.cs:12-54,82-112,133-147,150-199(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 -
docs/guide/durability/sagas.md:9-17,30-45,57-74,89-93,157-162(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 -
src/Wolverine/Saga.cs:5-36,40-48(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 -
src/Wolverine/Runtime/WolverineRuntime.cs:25-31,40-83,93-121,169-223(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 ↩5 -
docs/guide/handlers/index.md:3-6,32-36,53-56,63-76,93-105,142-147(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 -
src/Wolverine/Runtime/HandlerPipeline.cs:24-35,56-66,68-108,110-163,165-195(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 ↩4 ↩5 -
docs/guide/messaging/transports/local.md:3-7,12-27,55-61,88-99,118-126(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 -
docs/guide/messaging/transports/tcp.md:1-7,13-31,47-75,79-97(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2 ↩3 -
docs/guide/durability/idempotency.md:4-14,19-27(commit055ec9e611d37dae8e53404d8e57c35165b0d96d) ↩ ↩2