Repository navigation
Conversation
… when the fleet has published the owner's URL, instead of answering 409 not_ring_owner
A platform that balances requests across a fleet's instances reaches a non-owner for most streams. Each such
request cost the client a 409 and a replay, and an unpinned retry lands at random again: on Habanero's
services bench, 64 unpinned appends saw 6,383 replays and 4,628 errors in 30 s, at a quarter of the pinned rate.
Asked for by the owner, 2026-10-31.
The change: a layer inside track_inflight, on data-plane routes only. When the handler answers 409 with
Streams-Replay-To and the trusted peer table holds the owner's URL, the request is sent once to the owner,
marked Streams-Forwarded, and the client gets the owner's answer, streamed, with Streams-Forwarded-To. A
request marked Streams-Forwarded is never forwarded again, so a forward is one hop. The body is not buffered
by the layer: the handler reads it through a deferred body, so an unread body streams to the owner, and a body
the handler read whole within 64 KiB is forwarded from the frames it read, which share its bytes. A larger
body, an unknown URL, or a refused connection leaves the 409. A failure after the request was sent answers
503 forward_failed with Retry-After: 1, because the owner may have applied it.
Canonical owner: http::forward::to_owner.
Red: dst::dst_tests::forward_to_owner, before the layer was wired:
create fwd1: 409 {"error":{"code":"not_ring_owner","message":"shard 00 belongs to inst-b"}}
(src/dst/tests/forward_to_owner.rs:57)
Green: forward_to_owner (8), seal_fence_relay (10), livefeed_ownership (8).
Gate: GATEDONE. The release suite: 2,324 passed, 0 failed.
Controls: a request already forwarded, no URL, an unreachable owner, and a body past 64 KiB each keep the 409.
seal_fence_relay's redirect test and livefeed_ownership's typed refusal now mark their requests as already
forwarded; a new test pins the forwarded close.
Known window: a non-owner whose create was forwarded caches the stream's absence for the registry's 5 s TTL
and answers 404 there until it passes (recorded in the edge change).
Ledgers: owners.json (forward_to_owner), test inventory, mutation owners (http_forward) and measured sizes
(queue_maintenance 124 -> 125 was already on slate), DST README, WIRE-MATRIX. Formal: none. Edge change #235.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
A Streams instance that doesn't own a stream's shard now forwards a data-plane request once to the owner, when the fleet has published the owner's URL. It used to answer
409 not_ring_ownerand leave the replay to the client.Why
A platform that balances requests across a fleet's instances reaches a non-owner for most streams. Each such request cost a 409 and a replay, and an unpinned retry lands on a random instance again. On Habanero's services bench (a cell of 4 behind an edge, 141 ms away), 64 unpinned appends got 95 appends a second, against 343 pinned. They saw 6,383 replays and 4,628 errors in 30 s.
What changes
A layer inside
track_inflight, on data-plane routes only (live_wait::data_plane), insrc/http/forward.rs. Its trigger:Streams-Replay-To;Streams-Forwarded.When all three hold:
Streams-Forwarded: <instance marker>. A marked request is never forwarded again; its 409 is answered as before.Streams-Forwarded-To: <owner>.503 forward_failedwithRetry-After: 1. The owner may have applied the request, so the client must not replay it as new.Known window: a non-owner whose create was forwarded caches the stream as absent for the registry's 5 s TTL. Until it passes, it answers 404 for that stream; a 404 names no owner, so it isn't forwarded.
Records
owners.json, test inventory, thehttp_forwardmutation owner with re-measured sizes, and the DST README.queue_maintenance124 → 125 in the sizes file was already onslate.Tests
create fwd1: 409 {"error":{"code":"not_ring_owner","message":"shard 00 belongs to inst-b"}}before the layer was wired.dst::dst_tests::forward_to_owner, 8 tests: append, product append, create, live-feed connect, and the controls (already forwarded, no URL, unreachable owner, a body past 64 KiB). Alsoseal_fence_relay::a_non_owner_raw_close_takeover_installs_then_forwards.seal_fence_relay's redirect test now marks its request as already forwarded, so it still pins the 409.livefeed_ownership's typed refusal does the same.scripts/gate.shGATEDONE. The release suite: 2,324 passed, 0 failed.Breaking change
A client of a fleet that publishes peer URLs now gets, at a non-owner, the owner's answer where it used to get a 409. A router or SDK that followed
Streams-Replay-Tosees fewer 409s. It still has to handle them in the cases above.🤖 Generated with Claude Code