Repository navigation
fix: RMQ.Async producer moves confirm handlers to a replacement channel - #4582
Conversation
Root cause: RmqMessageProducer attached OnPublishSucceeded/OnPublishFailed to BasicAcksAsync/BasicNacksAsync only when Channel was null before EnsureBrokerAsync. The gateway replaces a closed channel in place and only nulls Channel on dispose, so a replacement channel never got the handlers: its publishes raised no confirmation and their pending entries were never settled. The producer now tracks the channel its handlers are attached to and compares by reference on each send, detaching from the old channel and attaching to the new one. Dispose detaches from the tracked channel rather than the current one. Further scope approved at Confirm (clearing pending confirmations on a switch, serialising the attach, the dispose guard) follows in later commits. Refs #4578 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SpjnqGWbARr3Z3ofGc6C2x
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SpjnqGWbARr3Z3ofGc6C2x
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SpjnqGWbARr3Z3ofGc6C2x
|
@claude Let's review the following. Please pay attention to the following in the comments when scoping the review: "Confirm first planned a wider fix: clear pending confirmations on a channel switch, guard the dispose wait, and lock the attach. Writing tests for those showed none of them can fail on a single-threaded send path once this fix is in. In tracking mode each send settles its own entry before BasicPublishAsync returns, and a new channel's tags overwrite older entries with the same tag. The real remaining risk is concurrent sends on one producer. It shows up three ways: duplicate delivery tags, a failed send's finally removing another channel's entry, and a double attach. That is one design problem, recorded on #4577: #4577 (comment) Also found during verification: #4581, where the RMQ.Sync and RMQ.Async dispatcher tests share queue names with different durability, so the two suites conflict when they run on one broker. This does not affect CI." |
|
Claude finished @iancooper's task in 1m 32s —— View job PR review: RMQ.Async confirm handlers move to replacement channel
Verdict: The fix is correct and small. It matches the root cause, and the regression test pins the behaviour against a real broker. I found one small consistency problem worth fixing (below) and a few nits. Nothing blocks the merge. Scope checkI reviewed this against the scope you gave: a single-threaded send path, with concurrency left to #4577 and the test-queue clash left to #4581.
Finding: the IOException catch leaves
|
…irmHandlers The IOException catch removed the confirm handlers from the failed channel by hand, leaving _confirmChannel pointing at it. Use the existing helper so the field is cleared too, keeping the reference check in ListenForConfirmsOnChannel accurate on every path. Addresses review feedback on #4582. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SpjnqGWbARr3Z3ofGc6C2x
Symptom
The RMQ.Async
RmqMessageProducerstopped raising publish confirmations once its channel was replaced. A channel gets replaced after an IOException reset, a broker-side channel close, or another gateway dropping the shared pooled connection. After that:OnMessagePublishednever fired again, so outbox entries were never marked dispatched and were resent as duplicates;WaitForConfirmsTimeOutInMilliseconds.Root cause
The producer attached
OnPublishSucceeded/OnPublishFailedtoBasicAcksAsync/BasicNacksAsynconly whenChannelwas null beforeEnsureBrokerAsync.RmqMessageGateway.ConnectToBrokerAsyncreplaces a closed channel in place, andChannelonly goes back to null on dispose. So a replacement channel never got the handlers.The channel is created with publisher-confirmation tracking on, so publishes on the new channel still succeeded. Their pending entries were simply never settled.
Evidence:
The full record is in
bugfixes/0055-rmq-async-confirm-resubscribe/bugfix.md.Fix
This follows #4567's fix for RMQ.Sync, adapted for v7:
_confirmChannel) and compares it by reference on each send. When the channel has changed, it detaches the handlers from the old channel and attaches them to the new one.Channelcurrently is.ConfirmSelectis needed.Detaching after the IOException reset is safe in v7, so it is unchanged. Disposing an
AutorecoveringConnectionclears its channel list but does not dispose the channels, so removing handlers does not throw. That is unlike the v6ObjectDisposedExceptionfixed in #4567.Tests
MessagingGateway/Proactor/When_the_channel_is_replaced_should_confirm_messages_sent_on_the_new_channel.cs, run against a real broker.ConfirmCountingRmqChannel, a forwardingDispatchProxyoverIChannelthat counts confirm subscribers;ConfirmCountingRmqProducer, which keeps every channel the producer opens.Paramore.Brighter.RMQ.Async.Testswith CI's filter: 257 passed, 0 failed, on both net9.0 and net10.0.Category=RMQNativeDelay: 103 passed, 0 failed.Scope
Confirm first planned a wider fix: clear pending confirmations on a channel switch, guard the dispose wait, and lock the attach. Writing tests for those showed none of them can fail on a single-threaded send path once this fix is in. In tracking mode each send settles its own entry before
BasicPublishAsyncreturns, and a new channel's tags overwrite older entries with the same tag.The real remaining risk is concurrent sends on one producer. It shows up three ways: duplicate delivery tags, a failed send's
finallyremoving another channel's entry, and a double attach. That is one design problem, recorded on #4577: #4577 (comment)Also found during verification: #4581, where the RMQ.Sync and RMQ.Async dispatcher tests share queue names with different durability, so the two suites conflict when they run on one broker. This does not affect CI.
Fixes #4578
🤖 Generated with Claude Code
https://claude.ai/code/session_01SpjnqGWbARr3Z3ofGc6C2x