Skip to content

fix(sources): [OBE-11555] release the request-limiter permit before the ack write - #143

Open
JuanMantica45 wants to merge 2 commits into
Sentinel-One:masterfrom
JuanMantica45:oom-tcp-ack-permit
Open

fix(sources): [OBE-11555] release the request-limiter permit before the ack write#143
JuanMantica45 wants to merge 2 commits into
Sentinel-One:masterfrom
JuanMantica45:oom-tcp-ack-permit

Conversation

@JuanMantica45

Copy link
Copy Markdown
Contributor

What

handle_stream held its RequestLimiterPermit across stream.write_all of the acknowledgement. A peer that stopped draining its receive window could park a permit indefinitely and starve every other connection on the source.

The permit is now released first. The ack write additionally gets a 30-second timeout so the connection itself is reclaimed.

Why 30s is safe

write_all only needs to hand a few bytes to the kernel send buffer — it does not wait for the peer's TCP ACK. With a default SO_SNDBUF, a 6-byte ack cannot block unless the peer has already stopped reading long enough to fill the buffer. Retransmission, RTT and congestion are absorbed by the kernel and cannot trigger the timeout, so it fires only against a genuinely stuck peer. It also sits below the sinks' 60s request timeout.

Testing

Replaces a placeholder test that asserted nothing (empty body, "verified by code inspection"). The ack write is extracted into write_ack, testable over tokio::io::duplex, with coverage for the success, timeout, slow-but-progressing and hangup paths plus the permit ordering the fix depends on. 9 passing.

Jira: OBE-11555

handle_stream held its RequestLimiterPermit across stream.write_all of the
acknowledgement. The permit exists to bound in-flight decoded events, and that
purpose is already served once send_batch and receiver.await complete, so a peer
that stopped draining its receive window could park a permit for as long as it
liked and starve every other connection on the source.
The permit is now released first. The ack write additionally gets a 30-second
timeout so the connection itself is reclaimed: write_all only needs to hand a
few bytes to the kernel send buffer, so it cannot block unless the peer has
already stopped reading long enough to fill it -- retransmission and congestion
are absorbed by the kernel and cannot trigger the timeout.
Replaces a placeholder test that asserted nothing. The ack write is extracted
into `write_ack`, which is testable over tokio::io::duplex, with coverage for
the success, timeout, slow-but-progressing, and hangup paths plus the permit
ordering the fix depends on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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

@JuanMantica45