open-webui/backend/open_webui
Classic298 e30ed01b05
perf: stream pure passthrough proxy responses by network chunk instead of by line (#27384)
stream_wrapper without a content handler iterates aiohttp's response.content, which reads line by line: every line costs a buffer scan, a slice, a bytes concat, a generator resume and its own ASGI response message. A typical SSE event is two lines (the data line and the blank separator), so every upstream token event became two yields and two transport writes even on routes where the body is never inspected.

stream_wrapper now takes passthrough=True, which iterates response.content.iter_any(): the exact same bytes, one yield per network read, no line scanning. It is applied only to routes no internal consumer parses line-by-line: the ollama pull/push/create/generate proxies and its v1 completions, chat completions, messages and responses endpoints, plus the openai embeddings, responses and catch-all proxies. The two internally consumed chat routes keep line iteration, which the streaming middleware and the Ollama-to-OpenAI converter require; the ollama send_request signature documents that constraint.

Benchmark (local aiohttp SSE server, 500 events, consumed through stream_wrapper):

| metric | before (readline) | after (iter_any) |
| --- | --- | --- |
| stream consumption time | 1.46 ms | 0.62 ms |
| generator yields + response writes per stream | 1000 | 1 |

The single yield is a loopback artifact (the whole body arrives in one buffered read); over a real network it becomes one yield per TCP read instead of two per SSE event.

Functionally verified: line mode and passthrough mode produce byte-identical output for the same stream, and passthrough always yields fewer, larger chunks.
2026-07-27 00:58:24 -04:00
..
data refac: mv backend files to /open_webui dir 2024-09-04 16:54:48 +02:00
internal perf: cut per-request database session overhead (#27385) 2026-07-23 17:49:48 -05:00
migrations chore: format 2026-07-27 00:12:47 -04:00
models chore: format 2026-07-27 00:12:47 -04:00
retrieval refac 2026-07-27 00:54:28 -04:00
routers perf: stream pure passthrough proxy responses by network chunk instead of by line (#27384) 2026-07-27 00:58:24 -04:00
socket refac 2026-07-26 23:49:03 -04:00
static refac 2026-07-20 22:27:13 -04:00
storage refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
tools refac 2026-07-27 00:27:38 -04:00
utils perf: stream pure passthrough proxy responses by network chunk instead of by line (#27384) 2026-07-27 00:58:24 -04:00
__init__.py refac 2026-06-17 03:01:11 +02:00
alembic.ini fix: Alembic CLI commands from failing 2025-08-15 04:17:47 -04:00
config.py chore: format 2026-07-27 00:12:47 -04:00
constants.py refac 2026-06-29 05:46:51 -05:00
env.py fix: Set default Redis socket timeout to None (#27104) 2026-07-27 00:30:00 -04:00
events.py refac 2026-07-26 19:10:41 -04:00
functions.py refac 2026-07-23 03:39:56 -04:00
main.py chore: format 2026-07-27 00:12:47 -04:00
tasks.py refac 2026-07-26 22:45:11 -04:00