open-webui/backend/open_webui/utils
Classic298 45e23c3ad0
perf: eliminate 2 redundant full chat deserialization on every message send (#21596)
* perf: eliminate 2 redundant full chat deserialization on every message send (#162)

Problem:
Every message send triggered get_chat_by_id_and_user_id which loads the
entire Chat row — including the potentially massive JSON blob containing
the full conversation history — even when the caller only needed a
simple yes/no ownership check or a single column value.

Two call sites in the message-send hot path were doing this:

1. main.py ownership verification: loaded the entire chat object including
   all message history JSON, then checked `if chat is None`. The JSON blob
   was immediately discarded — only the existence of the row mattered.

2. middleware.py folder check: loaded the entire chat object including all
   message history JSON, then read only `chat.folder_id` — a plain column
   on the chat table that requires zero JSON parsing.

Fix:
- Added `chat_exists_by_id_and_user_id()`: uses SQL EXISTS subquery which
  returns a boolean without loading any row data. The database can satisfy
  this from the primary key index alone.

- Added `get_chat_folder_id()`: queries only the `folder_id` column via
  `db.query(Chat.folder_id)`, which tells SQLAlchemy to SELECT only that
  single column instead of the entire row.

Both new methods preserve the same error handling semantics (return
False/None on exception) and user_id filtering (ownership check) as
the original get_chat_by_id_and_user_id.

Impact:
- Best case (typical): eliminates deserializing 2 full chat JSON blobs per
  message send. For long conversations (hundreds of messages with tool
  calls, images, file attachments), this blob can be multiple megabytes.
- Worst case: no regression — the new queries are strictly cheaper than
  the old ones (less data transferred, less Python object construction,
  no Pydantic model_validate overhead).
- The 3 remaining full chat loads in process_chat_payload (load_messages_from_db,
  add_file_context, chat_image_generation_handler) are left untouched as
  they genuinely need the full history and require separate analysis.

* Address maintainer feedback: rename method and inline call (#166)

- Rename chat_exists_by_id_and_user_id -> is_chat_owner
- Remove intermediate chat_owned variable; call is_chat_owner directly in if condition
2026-02-21 14:53:31 -06:00
..
images refac/fix: comfyui filter output node type 2025-12-30 12:24:48 +04:00
mcp Merge pull request #21485 from Classic298/claude/fix-mcp-ssl-check-0janH 2026-02-19 14:08:15 -06:00
telemetry chore: format 2026-02-11 16:24:11 -06:00
access_control.py chore: format 2026-02-11 16:24:11 -06:00
actions.py refac 2026-02-11 16:40:40 -06:00
anthropic.py refac 2026-02-21 14:15:32 -06:00
audit.py chore: format 2026-02-11 16:24:11 -06:00
auth.py refac 2026-02-19 16:29:19 -06:00
channels.py feat: channel/thread @ model 2025-09-17 00:49:44 -05:00
chat.py refac 2026-02-16 15:32:28 -06:00
code_interpreter.py chore: format 2026-02-11 16:24:11 -06:00
embeddings.py chore: format 2026-02-11 16:24:11 -06:00
files.py refac 2026-01-28 01:18:39 +04:00
filter.py chore/perf: Remove old SRC level log env vars with no impact (#20045) 2025-12-20 08:16:14 -05:00
groups.py refac/enh: db session sharing 2025-12-29 00:21:18 +04:00
headers.py refac 2026-02-06 03:23:37 +04:00
logger.py chore: format 2026-02-11 16:24:11 -06:00
middleware.py perf: eliminate 2 redundant full chat deserialization on every message send (#21596) 2026-02-21 14:53:31 -06:00
misc.py fix: resolve backend execution deadlock when syncing stats with cyclic chat history (#21681) 2026-02-20 23:04:36 -05:00
models.py refac 2026-02-16 23:52:32 -06:00
oauth.py refac 2026-02-20 16:55:06 -06:00
payload.py chore: format 2026-02-11 16:24:11 -06:00
pdf_generator.py chore: remove unnecessary Path conversions 2025-03-04 19:53:52 +02:00
plugin.py refac 2026-02-19 14:14:36 -06:00
rate_limit.py feat: signin rate limit 2025-12-02 03:52:38 -05:00
redis.py REDIS_RECONNECT_DELAY as positive float for handle retry delay on timeout/connection errors (#21021) 2026-01-29 17:13:03 +04:00
response.py refac: "tool_calls" finish reason support 2026-02-16 00:53:01 -06:00
sanitize.py chore: format 2026-02-11 16:24:11 -06:00
security_headers.py chore: format 2024-11-30 23:36:30 -08:00
task.py chore: format 2026-02-11 16:24:11 -06:00
tools.py refac 2026-02-19 14:06:24 -06:00
validate.py chore: format 2026-02-11 16:24:11 -06:00
webhook.py refac 2026-01-08 00:42:29 +04:00