BrighterCommand / BrighterCommand/Brighter
OutboxProducerMediator: the sync resilience path returns the delegate instead of invoking it, so the send never happens
- Dominant language
- C#
- Stars
- 2.5k
- Forks
- 296
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 21
Description
`OutboxProducerMediator.cs:1388`:
```csharp
if (requestContext?.ResilienceContext != null)
{
resiliencePipeline.Execute(_ => action, requestContext.ResilienceContext);
}
else
{
resiliencePipeline.Execute(action);
}
```
`_ => action` is a lambda that **returns** `action`. The pipeline invokes the lambda, receives an `Action`, and discards it. The delegate is never called, so **the send silently does not happen** — no exception, no log, nothing to notice.
The `else` branch is correct, and so is the async twin at `:1417`, which makes the shape of the bug easy to see side by side:
```csharp
// :1417 — correct: the delegate is invoked
await resiliencePipeline
.ExecuteAsync(async context => await send(context.CancellationToken), requestContext.ResilienceContext)
.ConfigureAwait(continueOnCapturedContext);
```
### Reachability
**Dead today, live the moment anything assigns `RequestContext.ResilienceContext`.** Nothing in the repository currently does, which is why no test catches it. That also means the day someone starts using the resilience context — the feature this branch exists to serve — messages start disappearing on the sync path only.
The failure mode is the worst kind: a successful-looking `Post`/`ClearOutbox` with no message sent and nothing in the logs.
### Suggested fix
```csharp
resiliencePipeline.Execute(_ => action(), requestContext.ResilienceContext);
```
with a test that asserts the action ran when a `ResilienceContext` is present — the assertion that would have caught it is "was the delegate invoked", not "did the call throw".
Found during review of #4302 / #4331.
Contributor guide
Assessment
This issue has not been assessed yet.