Skip to content

Instantly share code, notes, and snippets.

@dodyg
Created February 25, 2026 13:54
Show Gist options
  • Select an option

  • Save dodyg/e7139f0f37323e6cf1af5f1aa5f9e28f to your computer and use it in GitHub Desktop.

Select an option

Save dodyg/e7139f0f37323e6cf1af5f1aa5f9e28f to your computer and use it in GitHub Desktop.
Wolverine event system research report

Executive Summary

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

Architecture/System Overview

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      │
└───────────────────────────────────────────┘   └─────────────────────────────┘

Component Deep-Dive

1) Programming model and APIs

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

2) Routing, endpoints, and transport abstraction

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

3) Runtime execution pipeline

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

4) Durability model (inbox/outbox/deadletters/recovery)

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

5) Saga orchestration and long-running workflows

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

6) Handler model and code generation

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

Data Flow (Practical)

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

Deployment & Operations Characteristics

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

Key Repositories Summary

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

Confidence Assessment

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

Footnotes

  1. src/Wolverine/IMessageBus.cs:3-44,47-58,100-192 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4 5

  2. docs/guide/messaging/message-bus.md:1-58,66-76,98-109 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3

  3. src/Wolverine/Configuration/Endpoint.cs:54-75,90-109,166-197,214-240 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4 5

  4. docs/guide/messaging/subscriptions.md:1-4,21-35,93-109 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4

  5. docs/guide/messaging/transports/index.md:7-22 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3

  6. docs/guide/durability/index.md:8-16,17-22,76-84,196-203 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4

  7. src/Wolverine/DurabilitySettings.cs:6-34,39-52,86-124,133-160 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4 5

  8. src/Wolverine/Persistence/Durability/DurableSendingAgent.cs:12-54,82-112,133-147,150-199 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3

  9. docs/guide/durability/sagas.md:9-17,30-45,57-74,89-93,157-162 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3

  10. src/Wolverine/Saga.cs:5-36,40-48 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3

  11. src/Wolverine/Runtime/WolverineRuntime.cs:25-31,40-83,93-121,169-223 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4 5

  12. docs/guide/handlers/index.md:3-6,32-36,53-56,63-76,93-105,142-147 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4

  13. src/Wolverine/Runtime/HandlerPipeline.cs:24-35,56-66,68-108,110-163,165-195 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3 4 5

  14. docs/guide/messaging/transports/local.md:3-7,12-27,55-61,88-99,118-126 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2

  15. docs/guide/messaging/transports/tcp.md:1-7,13-31,47-75,79-97 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2 3

  16. docs/guide/durability/idempotency.md:4-14,19-27 (commit 055ec9e611d37dae8e53404d8e57c35165b0d96d) 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment