[Bug] BasicPublishAsync hangs after RabbitMQ server restart #1929
Closed
MarcoBarbieri90
started this conversation in
General
Replies: 2 comments 2 replies
This is not a bug, this how TCP works. See Heartbeats, including the part on low values and the risk of false positives, and Publisher Confirms. |
2 replies
|
Thank you for the reproduction steps @MarcoBarbieri90 - please continue discussion in #1930 |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Describe the bug
Environment
Description
We are experiencing a hang in BasicPublishAsync after restarting the RabbitMQ Windows service while publishing at high throughput (~50,000 messages every 7 seconds) with AutomaticRecoveryEnabled = true. The severity of the issue depends on whether publisher confirms are enabled or not.
When publisher confirms are disabled (publisherConfirmationsEnabled: false, publisherConfirmationTrackingEnabled: false), BasicPublishAsync silently hangs for approximately 3 minutes before automatically resuming. During this time, IConnection events (ConnectionShutdownAsync, RecoverySucceededAsync, ConnectionRecoveryErrorAsync) are not fired immediately — they are delayed by the same ~3 minutes, making them effectively useless for any timely recovery logic.
When publisher confirms are enabled (publisherConfirmationsEnabled: true, publisherConfirmationTrackingEnabled: false), the situation is worse. The IConnection events are still delayed by ~3 minutes and the connection does eventually recover, but BasicPublishAsync hangs indefinitely — even after full recovery, the publisher never resumes and no exception is ever thrown.
Root Cause
Both scenarios share the same underlying root cause, observed via the Visual Studio Task Debugger.
During the hang, the Task window reveals the following deadlock-like situation:
In the publisher without confirms, the Task window reveals the following call chain blocked at shutdown:

HandleConnectionCloseAsync(cmd, cancellationToken) inside Channel.cs is blocked attempting to write a frame to the SocketFrameHandler.
The internal Channel (bounded capacity: 128, FullMode: Wait) is full.
The reader task (WriteLoopAsync()) that drains this channel exits immediately when the RabbitMQ Windows service is stopped, leaving the channel permanently full and all writers blocked.
This means that when the server goes down, the write loop exits but the channel is never drained, causing any subsequent write attempt to wait indefinitely until automatic recovery eventually reconnects and unblocks the pipeline (~3 minutes later).
In the publisher confirms scenario, an additional problem compounds the above.

The Task window reveals the following call chain blocked at shutdown:
MaybeHandlePublisherConfirmationTcsOnChannelShutdownAsync
└─> SemaphoreSlim.WaitUntilCountOrTimeoutAsync ← blocked indefinitely
OnChannelShutdownAsync triggers MaybeHandlePublisherConfirmationTcsOnChannelShutdownAsync, which tries to acquire a SemaphoreSlim to complete or cancel all pending publisher confirm TaskCompletionSources.
This SemaphoreSlim is never released during shutdown (likely held by a write operation that is itself blocked — same root cause as issue #XXXX).
As a result, all pending BasicPublishAsync calls remain awaiting a confirm that will never arrive, even after the connection and channel are recovered.
Reproduction steps
Scenario A — confirms disabled (publisherConfirmationsEnabled: false, publisherConfirmationTrackingEnabled: false):
Publisher - No Confirms.txt
Observe:
After ~3 minutes, IConnection events fire and the connection recovers.
BasicPublishAsync hangs silently for ~3 minutes.
After ~3 minutes, publishing resumes automatically.
Scenario B — confirms enabled (publisherConfirmationsEnabled: true, publisherConfirmationTrackingEnabled: false):
Publisher - Confirms.txt
Observe:
BasicPublishAsync hangs.
After ~3 minutes, IConnection events fire and the connection recovers.
BasicPublishAsync remains blocked indefinitely — the publisher never resumes.
No exception is ever thrown.
Expected behavior
Additional context
No workaround has been found so far.
Are there any recommended workarounds while this is being investigated?
All reactions