open-webui/backend/open_webui
Claude 498a04dc6c
feat(plugins): cross-worker tool + function cache invalidation via Redis
Bug: request.app.state.TOOLS / FUNCTIONS are per-worker Python dicts.
Save on worker A does not touch worker B's cache, so worker B keeps
serving the stale compiled module until the process restarts.
utils/tools.py's invocation path was also completely cache-blind —
a bare dict.get with no content-hash fallback, so even same-worker
edits skipped the TOOL_CONTENTS check and served the first-seen
module forever.

Symptom: editing a tool in the Workspace UI, triggering a chat, and
watching the OLD code execute until backend restart. Confirmed on a
multi-worker deployment (UVICORN_WORKERS > 1) with Redis.

Fix — three parts:

1. backend/open_webui/utils/plugin_cache.py (new)
   * publish_invalidation(app, kind, id)
     - drops the local TOOLS/FUNCTIONS + _CONTENTS entry
     - publishes {kind, id} on REDIS_PLUGIN_CACHE_CHANNEL
   * plugin_cache_listener(app)
     - subscribes on startup, drops caches on every inbound message
     - mirrors the existing redis_task_command_listener pattern
   * falls back to pure local invalidation when Redis is unconfigured

2. utils/tools.py
   * invocation path swapped from `TOOLS.get(tool_id)` to
     `await get_tool_module_from_cache(request, tool_id)`, which does
     content-hash invalidation from DB. Covers edits that predate or
     race the Redis pub/sub message.

3. routers/tools.py + routers/functions.py
   * create / update / delete / toggle / toggle_global all call
     publish_invalidation after the DB mutation commits.
   * toggle_function_by_id + toggle_global_by_id gained a `request`
     parameter they were missing.

main.py lifespan starts the listener alongside the task listener and
cancels it on shutdown. No new env vars — reuses REDIS_URL and
REDIS_KEY_PREFIX.

Single-worker deployments still work: publish_invalidation
unconditionally drops the local cache before trying to publish.
2026-04-20 14:24:33 +00:00
..
data refac: mv backend files to /open_webui dir 2024-09-04 16:54:48 +02:00
internal refac 2026-04-20 18:47:53 +09:00
migrations chore: format 2026-04-19 22:45:54 +09:00
models refac 2026-04-20 03:35:17 -04:00
retrieval refac 2026-04-20 08:34:15 +09:00
routers feat(plugins): cross-worker tool + function cache invalidation via Redis 2026-04-20 14:24:33 +00:00
socket refac 2026-04-17 13:29:51 +09:00
static chore: format 2026-04-19 22:45:54 +09:00
storage refac 2026-04-12 19:08:30 -05:00
test refac 2026-03-17 17:58:01 -05:00
tools refac 2026-04-19 23:42:09 +09:00
utils feat(plugins): cross-worker tool + function cache invalidation via Redis 2026-04-20 14:24:33 +00:00
__init__.py refac (#22987) 2026-03-24 15:41:26 -05:00
alembic.ini fix: Alembic CLI commands from failing 2025-08-15 04:17:47 -04:00
config.py chore: format 2026-04-19 22:45:54 +09:00
constants.py chore: format 2026-04-14 17:27:31 -05:00
env.py refac 2026-04-20 09:21:30 +09:00
functions.py refac 2026-04-17 14:15:36 +09:00
main.py feat(plugins): cross-worker tool + function cache invalidation via Redis 2026-04-20 14:24:33 +00:00
tasks.py refac 2026-03-17 17:58:01 -05:00