You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Wolverine.HTTP: opt-in 409 ProblemDetails mapping for ConcurrencyException and StreamLockedException #4512
Ship an opt-in, out-of-the-box mapping in Wolverine.HTTP from the Critter Stack concurrency failures to an HTTP 409 ProblemDetails response, so users do not have to hand-write the middleware in docs/guide/http/exception-handling.md for every service.
Today
Nothing in Wolverine.Http maps these exceptions to a status code. An unhandled ConcurrencyException from a Marten, Polecat or Fisher session, or a StreamLockedException from FetchForExclusiveWriting, escapes as a 500. The documented workaround is a user-authored middleware class with two OnException overloads plus opts.AddMiddleware(typeof(MartenConcurrencyExceptionMiddleware), chain => chain.IsTransactional), and an IHttpPolicy to advertise 409 in OpenAPI. That is four pieces the user has to know exist and get right, and the doc itself has to warn that catching only ConcurrencyException misses StreamLockedException (which does not derive from it in Marten or Polecat).
Proposed shape
Something like:
app.MapWolverineEndpoints(opts =>{opts.MapConcurrencyFailuresTo409();// name TBD});
that:
catches JasperFx.ConcurrencyException (covers EventStreamUnexpectedMaxEventIdException, DcbConcurrencyException, document revision/version failures, and SagaConcurrencyException) and returns ProblemDetails { Status = 409, Title = "Conflict", Detail = ex.Message };
also catches the store-specific lock types that are notConcurrencyExceptions: Marten.Exceptions.StreamLockedException and Polecat.Exceptions.StreamLockedException (Fisher has none, its exclusive methods are optimistic and throw EventStreamUnexpectedMaxEventIdException);
applies only to transactional chains by default, with the same predicate hook AddMiddleware takes;
stamps ProducesProblem(409) metadata on those chains so the OpenAPI document advertises it.
Whether ExistingStreamIdCollisionException belongs in the same mapping is a judgement call (it is a conflict, but usually a client bug rather than a race); it is reasonable to leave it out of the default and let the predicate/overloads add it.
Why now
A client has asked for this. It is also the kind of thing an AI-agent skill can only recommend as a copy-paste recipe today, and a one-line opt-in is a much better answer.
Activity
GH-4516: map an unknown tenant id to a 404 ProblemDetails instead of …
JasperFxGH-4512: one-line opt-in mapping concurrency failures to a 40…
Bump to 6.40.0 (#4608)