2 months ago
Service: web in project magnificent-integrity
Endpoint: POST /agent/chat
Issue: Railway's edge proxy buffers the entire SSE response to completion before delivering any bytes to clients
Evidence:
Server-side logs confirm events are emitted incrementally over 5-7 seconds
Local testing with python -m uvicorn app.main:app --host 0.0.0.0 --port $PORT streams correctly (Transfer-Encoding: chunked, no Content-Length)
Deployed endpoint delivers entire response with Content-Length header all at once after 60+ seconds
HTTP logs show totalDuration: 69183ms for a single request
Current headers already set: X-Accel-Buffering: no, Cache-Control: no-cache, Connection: keep-alive
These headers are ignored by the edge
Is there a configuration flag, edge setting, or known workaround for streaming responses on Railway? The edge appears to have a buffering policy that cannot be defeated by standard HTTP headers.
2 Replies
2 months ago
This thread has been opened as a bounty so the community can help solve it.
Status changed to Open Railway • 2 months ago
2 months ago
Server: railway-hikari
x-accel-buffering: no ← honored upstream, ignored by edge
x-railway-edge: railway/asia-southeast1-eqsg3a
Content-Length: 33867 ← buffered to completion
(no Transfer-Encoding: chunked)
(no Content-Encoding: gzip)
(no cf-ray / Cloudflare)
This rules out my hypotheses and pinpoints the culprit:
Not gzip — no content-encoding. So no-transform was a dead end (no compression was happening).
Not Cloudflare — no cf-ray. It's Railway's own edge proxy, railway-hikari.
Content-Length: 33867 = the edge read your entire response (including the 32 KB padding — that's why it's ~33 KB now), measured it, and sent one fixed-length body. It ignores X-Accel-Buffering: no.
So this is Railway's hikari edge buffering to completion, and none of the app-level levers (chunked, padding, heartbeat, no-transform, X-Accel-Buffering) can defeat it. Let me get current, specific info on hikari + streaming rather than guess again.
13 days ago
Content Length alone does not prove the edge buffered it because middleware can materialize streams.
Call the same service over railway.internal from another service to bypass the public edge.
If that streams incrementally the edge is responsible otherwise inspect your FastAPI middleware.