Skip to content

SSLSocket#write_nonblock: hand over up to 1 MB, convert only that (flaky NetHttp_Tls1) - #33

Merged
Largo merged 1 commit into
masterfrom
fix/flaky-net-http-write-timeout
Oct 27, 2026
Merged

Largo merged 1 commit into
masterfrom
fix/flaky-net-http-write-timeout

Conversation

@Largo

@Largo Largo commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Problem

NetHttp_Tls1 failed now and then on ubuntu (master's run for #28 on net10.0, #32's on net8.0) with [:write_timeout, false]: Net::WriteTimeout was raised, but more than 10 s after the start, for a write_timeout of 1 s.

Cause

  • net/protocol's write0 slices off what write_nonblock wrote and passes the rest back: str = str.byteslice(len, -len), a copy of the rest every call (CRuby shares the buffer there).
  • Transport#write_nonblock handed over at most 16 KB a call, and ran ConvertToBytes() on all of the data to do so.

For the test's 64 MB body that was two copies of ~60 MB per 16 KB record until the kernel buffers were full. Loopback buffers on Linux hold several MB, so that came to hundreds of records and gigabytes of copying before the 1 s timeout could even start. On Windows the buffers are small, which is why only ubuntu ever failed.

Fix

  • write_nonblock converts only the bytes it may send (GetBinarySlice).
  • It goes on with the next 16 KB record for as long as the last one completed at once, up to 1 MB a call. What it reports written is still what the kernel took, plus the record in flight.
  • The comments in ssl.rb and Docs/net-http-over-tls.md are updated.

Testing

Built locally for net10.0, and NetHttp_Tls1, NetHttp_TlsVerifyCallback1, NetHttp_PlainNoOpenSsl1, NetHttp_GemNetTls1, Ssl_NonBlocking1 and Puma_Tls1 pass on Windows. The flake only shows on ubuntu, where loopback buffers are large, so the ubuntu jobs are the ones that count.

NetHttp_Tls1's write_timeout check failed now and then on ubuntu
([:write_timeout, false]: Net::WriteTimeout came, but after more than
10 s). net/protocol's write0 slices off what write_nonblock wrote and
passes the rest back, a copy of the rest each time, and the transport
converted all of the data to bytes on every call to send its first
16 KB. For the test's 64 MB body that was two copies of ~60 MB per
16 KB record until Linux's loopback buffers (several MB) were full:
gigabytes of copying before the 1 s timeout could start.

write_nonblock now converts only what it may send, and goes on with
the next 16 KB record while the last one went out at once, up to 1 MB
a call; what it reports written is still what the kernel took plus
the record in flight.
@coderabbitai

coderabbitai Bot commented Oct 27, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 5 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a35c6bc4-5660-45f2-8e34-328de92875ff
Commits

Reviewing files that changed from the base of the PR and between 913b08c and 1e16971.

Files selected for processing: 3
  • Docs/net-http-over-tls.md
  • Src/Libraries/OpenSSL/OpenSSL.cs
  • Src/StdLib/ironruby/openssl/ssl.rb
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Largo
Largo merged commit b34a4df into master Oct 27, 2026
7 checks passed
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.

1 participant