Skip to content

Do not drop frames when a Netty frame write is interrupted - #2175

Merged
acogoluegnes merged 2 commits into
rabbitmq:mainfrom
ultramancode:fix/netty-write-frame-interrupt
Nov 12, 2026
Merged

acogoluegnes merged 2 commits into
rabbitmq:mainfrom
ultramancode:fix/netty-write-frame-interrupt

Conversation

@ultramancode

Copy link
Copy Markdown
Contributor

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 x in the boxes that apply

  • Bugfix (non-breaking change which fixes issue #NNNN)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation (correction or otherwise)
  • Cosmetics (whitespace, appearance)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating
the 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.

  • I have read the CONTRIBUTING.md document
  • I have signed the CA (see https://cla.pivotal.io/sign/rabbitmq)
  • All tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)
  • Any dependent changes have been merged and published in related repositories

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>
@acogoluegnes
acogoluegnes requested a balanced review from Copilot November 12, 2026 10:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
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

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
acogoluegnes merged commit b4e5a84 into rabbitmq:main Nov 12, 2026
7 checks passed
@acogoluegnes

Copy link
Copy Markdown
Contributor

@ultramancode Thanks!

@acogoluegnes

Copy link
Copy Markdown
Contributor

@Mergifyio backport v5.x

@mergify

mergify Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

backport v5.x

✅ Backports have been created

Details

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)
@ultramancode

Copy link
Copy Markdown
Contributor Author

@acogoluegnes
Thanks for catching the channel-close case! I've learned a lot from your follow-up work on my earlier PRs, too.

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.

3 participants