Skip to content

Durable HTTP transport never deletes the outgoing envelope (#3173)#3209

Merged
jeremydmiller merged 1 commit into
mainfrom
fix/durable-http-outbox-3173
Jun 23, 2026
Merged

Durable HTTP transport never deletes the outgoing envelope (#3173)#3209
jeremydmiller merged 1 commit into
mainfrom
fix/durable-http-outbox-3173

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

What

Fixes the durable HTTP transport redelivering successfully-processed messages forever (the Outgoing outbox count never drops).

Root cause

HttpSenderProtocol.SendBatchAsync posted the batch but never invoked the ISenderCallback:

await client.SendBatchAsync(_endpoint.OutboundUri, batch);
// no callback.MarkSuccessfulAsync(batch)  ← here

Every other transport's ISenderProtocol (Redis, Kafka, …) calls callback.MarkSuccessfulAsync(batch) on success / callback.MarkProcessingFailureAsync(batch, ex) on failure. That callback is what drives DurableSendingAgent.MarkSuccessfulAsyncDeleteOutgoingAsync, removing the outbox row. Without it, the outgoing envelope is never deleted and the durable sending agent re-sends it indefinitely.

Fix

  • HttpSenderProtocol.SendBatchAsync now MarkSuccessfulAsync on success and MarkProcessingFailureAsync on exception.
  • WolverineHttpTransportClient.SendBatchAsync (and the CloudEvents client) now EnsureSuccessStatusCode(), so a non-2xx response throws → is treated as a failure (requeue) rather than silently acknowledged and deleted.
  • Regression tests in HttpSenderTests: a successful batch acks (MarkSuccessfulAsync), a throwing client reports failure (MarkProcessingFailureAsync) and never acks.

Closes #3173

🤖 Generated with Claude Code

HttpSenderProtocol.SendBatchAsync sent the batch but never invoked the
ISenderCallback, so the DurableSendingAgent never deleted the outgoing envelopes
from the outbox — a successfully delivered message redelivered forever and the
Outgoing count never dropped. Mirror the other transport sender protocols
(Redis/Kafka): call MarkSuccessfulAsync(batch) on success and
MarkProcessingFailureAsync(batch, ex) on failure. Also make the transport client
EnsureSuccessStatusCode() so a non-2xx response is treated as a failure (requeue)
rather than silently acknowledged.

Adds regression coverage to HttpSenderTests for both the success-ack and
failure-requeue paths.

Closes #3173

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit d1b6f45 into main Jun 23, 2026
26 checks passed
This was referenced Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Durable HTTP transport never deletes the outgoing envelope - successful sends redeliver forever

1 participant