Skip to content

fix(streaming): use idle read_timeout for SSE, not total request timeout#5

Merged
ZhiXiao-Lin merged 1 commit into
mainfrom
fix/sse-idle-timeout
Jun 10, 2026
Merged

fix(streaming): use idle read_timeout for SSE, not total request timeout#5
ZhiXiao-Lin merged 1 commit into
mainfrom
fix/sse-idle-timeout

Conversation

@ZhiXiao-Lin

Copy link
Copy Markdown
Contributor

Problem

SSE/streaming responses were hard-killed after 5 minutes regardless of activity. Root cause: entrypoint/protocol/streaming_handler.rs passes a hardcoded 300 to proxy::streaming::forward_streaming, which set it as reqwest's RequestBuilder::timeout — a total request deadline that includes reading the streamed body. So every SSE stream died at 300s even with continuous data, and the a3s-gateway.io/request-timeout annotation had no effect on streams.

Fix

Move the streaming timeout to a client-level read_timeout (idle) in proxy/streaming.rs and drop the per-request total timeout. read_timeout resets on every byte, so a healthy stream with periodic keep-alive frames (the API emits one every ~10s) never trips it and can run indefinitely; only a genuinely silent upstream is reaped after the idle window. (RequestBuilder::read_timeout does not exist in reqwest 0.12; ClientBuilder::read_timeout does — hence the client-level placement.)

Non-streaming requests use a different client and are unaffected.

Verification

Built musl 1.0.10 (with --features kube,redis), deployed to prod gateway + edge, and ran an end-to-end endurance test: a real SSE stream through the gateway survived 340s (68 ticks) vs the old hard cut at 300s. Entry health 6/6 200 throughout.

Bumps version 1.0.7 → 1.0.10.

reqwest's RequestBuilder::timeout caps the WHOLE request including the
streamed body, so SSE/chunked responses were hard-killed after the
hardcoded 300s regardless of activity — every SSE stream died at 5 min.
Move to a client-level read_timeout (idle, reset on every byte): a healthy
stream with periodic keep-alive frames (~10s) never trips it and can run
indefinitely; only a genuinely silent upstream is reaped. Bump to 1.0.10.
@ZhiXiao-Lin ZhiXiao-Lin merged commit f3f48df into main Jun 10, 2026
@ZhiXiao-Lin ZhiXiao-Lin deleted the fix/sse-idle-timeout branch June 10, 2026 08:31
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