Wolverine 6.30.0
Wolverine 6.30.0 is a large release built around one headline feature — a new endpoint mode — plus the usual crop of transport fixes, and a couple of long-standing multi-tenancy and HTTP gaps closed.
EndpointMode.NativeAck
The main event. Buffered's throughput and partitioning with Inline's no-loss guarantee, and no database required.
A broker delivery is held unacknowledged while the envelope flows through an in-memory, optionally group-partitioned execution block, and is settled natively when the handler pipeline terminates. Nothing is acknowledged ahead of its handler, so work parked in a lane when a node goes away comes back rather than vanishing.
opts.ListenToRabbitQueue("orders")
.ProcessInParallelWithNativeAcks();The guarantee, stated exactly: no two messages sharing a group id execute concurrently. Ordering is per-slot best-effort, not per-group guaranteed; redelivery may reorder. Anything needing strict order under failure keeps the durable inbox.
Transport support is opt-in and default-closed — a transport must explicitly claim the mode, because most settlement models cannot express out-of-order completion. Adopted by RabbitMQ, Amazon SQS, Azure Service Bus, NATS JetStream, Redis Streams, Pulsar and GCP Pub/Sub (#3708, #4046, #4047, #4050, #4051, #4052, #4053).
Supporting work in the same wave:
- Lease renewal for queued envelopes on clocked transports — SQS, ASB, JetStream and Pub/Sub run a clock on an unsettled delivery, and the risk window is lane queue time plus handler time (#4048).
- In-memory idempotency guard, an opt-in duplicate filter for a mode with no inbox row to deduplicate against (#3710).
- Global partitioning across sharded queues (#3709).
- Listener mode coherence validation, which caught that RabbitMQ queues default to Inline — so sharded topologies were silently unpartitioned without an explicit
BufferedInMemory()(#3712, #4022). - A five-node chaos reproduction under webhook flood, measuring the real duplicate rate on abrupt node loss (#3713).
Multi-tenancy
- Conjoined EF Core tenancy now works when Marten owns the message store via
IntegrateWithWolverine(). Marten hands Wolverine anNpgsqlDataSourcerather than a connection string, andNpgsqlDataSource.ConnectionStringdeliberately omits the password — so there is a newDbDataSourceoverload ofAddDbContextWithWolverineManagedConjoinedTenancythat carries credentials through intact. A second defect on the same path is fixed too:IntegrateWithWolverine()never registered the tenant partitioning provider, soPartitionPerTenant()failed (#4044).
HTTP and event sourcing
[StreamState]and[StreamEvents]— new parameter attributes for handlers whose read is the raw stream rather than the folded aggregate, for timeline and audit shaped endpoints that[ReadModel]cannot express. Store-agnostic across Marten, Polecat and Fisher; Marten batches both fetches into a single round trip (#3627).- Marten concurrency conflicts as 409 — a documented, tested recipe for mapping optimistic-concurrency failures on
[WriteAggregate]endpoints toProblemDetailsinstead of an unhandled 500. Note thatStreamLockedExceptionderives fromMartenException, notConcurrencyException, so catching only the latter silently leavesFetchForExclusiveWritingreturning 500s (#3764). - Event Model slices per route —
HttpChainDescriptorandGrpcRpcDescriptornow carry the slice the route is, so a consumer walking endpoint by endpoint sees it next to the route rather than only through the assembled model (#4000).
Transport fixes
- Pulsar: requeue, scheduled retry and dead-letter routing implemented (#3797). A global failure rule was silently disabling every user error policy application-wide (#4075). Hot-tail listeners silently dropped deferred messages in every mode (#4060).
- GCP Pub/Sub: listener shutdown could hang on in-flight callbacks (#4065); exhausting
MaxTotalAckExtensionsilently delivered a concurrent duplicate rather than reporting anything (#4066); effective listener concurrency was not what the configuration implied, and the flow-control bound is global perSubscriberClientrather than per inner client (#4067).PubsubTopicOptions.OrderBygained a configuration surface (#4087). - Redis:
DeleteStreamEntryOnAcksilently never acked on Redis < 8.2, whereXACKDELis unsupported (#4058). - Ack reliability: a shared ack-attempt budget across stacked retry blocks, and terminal-failure classification for Azure Service Bus and SQS so a permanent settle failure stops rather than burning the whole budget (#4012).
Upgrading
Additive. EndpointMode.NativeAck is opt-in per endpoint and default-closed per transport, and MaximumBrokerRedeliveries defaults to off. Requires JasperFx 2.55.0.