Skip to content

The search box in the website knows all the secrets—try it!

For any queries, join our Discord Channel to reach us faster.

JasperFx Logo

JasperFx provides formal support for Marten and other JasperFx libraries. Please check our Support Plans for more details.

Part 6: Integrating Marten with Wolverine

Marten and Wolverine are a powerful combination for building reliable, distributed, and event-driven systems. Marten handles persistence (documents and events), while Wolverine provides messaging, transactional outbox/inbox support, background processing, and distributed coordination.

This integration serves two distinct purposes:

  1. Event-driven messaging and transactional command handling
  2. Coordinated background projection processing in distributed environments

Reliable Messaging with Aggregates

When using event sourcing, emitting events from domain aggregates is common — and often, we want to trigger side effects (notifications, follow-up commands, integration events). With just Marten, you'd need to handle messaging yourself, risking lost messages in case of failure.

With Wolverine:

  • You can use [AggregateHandler] to define aggregate command handlers.
  • Events and messages returned from the handler are saved and dispatched atomically.
  • Wolverine uses Marten’s outbox to store messages until the transaction commits.

Example:

cs
[AggregateHandler]
public static IEnumerable<object> Handle(PickupShipment cmd, FreightShipment shipment)
{
    if (shipment.Status != ShipmentStatus.Scheduled)
        throw new InvalidOperationException("Cannot pick up unscheduled shipment");

    yield return new ShipmentPickedUp(cmd.Timestamp);
    yield return new NotifyDispatchCenter(shipment.Id, "PickedUp");
}

Wolverine will:

  1. Load the FreightShipment using FetchForWriting (for optimistic concurrency)
  2. Pass the current aggregate and command to the handler
  3. Append the returned events to the stream
  4. Save the session
  5. Dispatch messages after commit

The outbox ensures exactly-once messaging. The inbox can guarantee that incoming messages are processed only once, even across retries.

Distributed Projections in Multi-Node Environments

If you run your freight system across multiple nodes (e.g. for horizontal scaling or redundancy), Marten’s async projection daemon needs coordination — to avoid multiple nodes processing the same projection.

Wolverine offers cluster-wide coordination:

  • Only one node will run each async projection or event subscription.
  • If a node fails, projection work is reassigned.
  • You can configure load balancing and capability-based projection routing (e.g., for blue/green deployments).

Configuration:

cs
await builder.ConfigureServices(services =>
{
    services.AddMarten(opts =>
        {
            opts.Connection(connectionString!);
            opts.AutoCreateSchemaObjects = AutoCreate.All; // Dev mode: create tables if missing
            opts.Projections.Add<DailyShipmentsProjection>(ProjectionLifecycle.Async);
            opts.Projections.Add<ShipmentViewProjection>(ProjectionLifecycle.Async);
        })
        .AddAsyncDaemon(DaemonMode.HotCold)
        .IntegrateWithWolverine(cfg =>
        {
            cfg.UseWolverineManagedEventSubscriptionDistribution = true;
        });
})
.StartAsync(cancellationToken);

This ensures that your projection daemon is managed by Wolverine’s distributed coordinator.

Summary

  • Messaging + Aggregates: Wolverine makes it easy to process commands, generate events, and send follow-up messages, all with transactional guarantees.
  • Cluster-safe Projections: In distributed deployments, Wolverine ensures that async projections are safely coordinated.
  • Inbox/Outbox: Wolverine ensures exactly-once delivery semantics across your freight and delivery system.

Together, Marten and Wolverine give you a solid foundation for a consistent, reliable freight management system — with minimal boilerplate and maximum safety.

Dispatch CenterOutboxMarten Event StoreWolverine HandlerAPIDispatch CenterOutboxMarten Event StoreWolverine HandlerAPISend PickupShipmentFetchForWriting(FreightShipment)Aggregate stateHandler emits ShipmentPickedUp + NotifyDispatchCenterAppend eventsEnqueue NotifyDispatchCenterSaveChanges (commit)CommittedPublish NotifyDispatchCenter tdbnj

INFO

You can download the source code zip file freight-shipping-tutorial.zip from this link.

  1. Ensure you have .NET 9.0 installed in your machine.
  2. Unzip the downloaded zip file and run the project using dotnet run, it will show you the list of commands for each tutorial page.
  3. You can set up the Postgres database as outlined in the docker-compose.yml file. Or run your own Postgres instance and update the connection string accordingly in appsettings.json file
  4. As an example, run dotnet run -- getting-started which executes the sample code in Getting Started page. Similarly the other list of commands will correspond to the respective tutorial pages accordingly.

Released under the MIT License.