Repository navigation
Do not drop frames when a Netty frame write is interrupted - #2175
Merged
acogoluegnes merged 2 commits intoNov 12, 2026
Merged
Conversation
With Netty IO, writeFrame waits for a non-writable channel to become writable before writing the frame. If the thread was interrupted while waiting, the frame was silently dropped. basicPublish returned as if the message had been sent, but it never reached the broker. When other frames of the same command had already been written, the broker received an incomplete command and closed the connection with UNEXPECTED_FRAME. writeFrame now keeps waiting when the thread is interrupted and restores the interrupt flag afterwards. The enqueuing timeout still bounds the wait, so an interrupted thread can block for up to that timeout before the frame is written or the write fails. Signed-off-by: Taewoong Kim <ktw2172@gmail.com>
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open issues
nettyChannel.get()can be null here if the channel callback hasn't executed yet, which would make… · New This test reaches into Netty internals (unsafe(),outboundBuffer()) which can be brittle across… · New The timeout conversionMILLISECONDS.toNanos(timeout.toMillis())truncates sub-millisecond… · New
What changed in this PR
Fixes a Netty I/O edge case where an interrupt during a non-writable wait could cause a frame to be silently dropped, resulting in partial commands on the wire and unexpected broker connection closures.
Changes:
- Update Netty frame write path to wait uninterruptibly (while still honoring the enqueue timeout) and restore the interrupt flag afterward.
- Add a regression test that simulates a non-writable Netty channel, interrupts the writer thread, and verifies the frame is eventually written.
| File | Description |
|---|---|
| src/main/java/com/rabbitmq/client/impl/NettyFrameHandlerFactory.java | Introduces an uninterruptible latch wait with preserved interrupt status to prevent frame drops on interrupt. |
| src/test/java/com/rabbitmq/client/test/NettyTest.java | Adds a regression test that forces channel non-writability, interrupts the writer, then verifies delivery and interrupt restoration. |
Review effort: Lite
Copilot stopped reviewing on behalf of
acogoluegnes due to an error
November 12, 2026 11:16
A thread waiting in writeFrame for a non-writable channel to become writable was released only by a writability change. Netty does not fire that event when the channel closes, so the thread stayed blocked until the enqueuing timeout elapsed. Now that the wait can no longer be interrupted, nothing could cut it short. The writability latch is now counted down when the channel becomes inactive. writeFrame then fails with an IOException instead of writing to a closed channel.
acogoluegnes
approved these changes
Nov 12, 2026
Contributor
|
@ultramancode Thanks! |
Contributor
|
@Mergifyio backport v5.x |
✅ Backports have been createdDetails
|
7 of 11 tasks
acogoluegnes
added a commit
that referenced
this pull request
Nov 12, 2026
Do not drop frames when a Netty frame write is interrupted (backport #2175)
Contributor
Author
|
@acogoluegnes |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


With Netty IO, writeFrame waits for the channel to become writable when it is not. If the thread is interrupted during this wait, the frame is silently dropped and basicPublish returns as if the message had been sent. If other frames of the same command were already written, the broker closes the connection with UNEXPECTED_FRAME.
This PR keeps waiting when the thread is interrupted and restores the interrupt flag afterwards. The enqueuing timeout still bounds the wait. The client already handles interrupts this way in BlockingCell.uninterruptibleGet.
As a trade-off, an interrupted thread can block for up to the enqueuing timeout. Throwing InterruptedIOException instead would not keep the connection, because the earlier frames of the command would already be on the wire.
I tested this against RabbitMQ 4.4.0 running in Docker on Java 8 and 21, by pausing the broker and interrupting a publisher. Before the change, messages were lost and the connection was closed. After the change, all messages were queued and the connection stayed open.
Types of Changes
What types of changes does your code introduce to this project?
Put an
xin the boxes that applyChecklist
Put an
xin the boxes that apply. You can also fill these out after creatingthe PR. If you're unsure about any of them, don't hesitate to ask on the
mailing list. We're here to help! This is simply a reminder of what we are
going to look for before merging your code.
CONTRIBUTING.mddocument