[PR #23896] feat(plugins): cross-worker tool + function cache invalidation via Redis #43059

Open
opened 2026-04-25 14:46:08 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/23896
Author: @Classic298
Created: 4/20/2026
Status: 🔄 Open

Base: devHead: claude/cross-worker-plugin-cache


📝 Commits (1)

  • 498a04d feat(plugins): cross-worker tool + function cache invalidation via Redis

📊 Changes

5 files changed (+145 additions, -7 deletions)

View changed files

📝 backend/open_webui/main.py (+4 -0)
📝 backend/open_webui/routers/functions.py (+18 -2)
📝 backend/open_webui/routers/tools.py (+4 -0)
backend/open_webui/utils/plugin_cache.py (+110 -0)
📝 backend/open_webui/utils/tools.py (+9 -5)

📄 Description

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.

Contributor License Agreement

Note

Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/23896 **Author:** [@Classic298](https://github.com/Classic298) **Created:** 4/20/2026 **Status:** 🔄 Open **Base:** `dev` ← **Head:** `claude/cross-worker-plugin-cache` --- ### 📝 Commits (1) - [`498a04d`](https://github.com/open-webui/open-webui/commit/498a04dc6c5baa6bf1de39b68cec4d8555bc8909) feat(plugins): cross-worker tool + function cache invalidation via Redis ### 📊 Changes **5 files changed** (+145 additions, -7 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/main.py` (+4 -0) 📝 `backend/open_webui/routers/functions.py` (+18 -2) 📝 `backend/open_webui/routers/tools.py` (+4 -0) ➕ `backend/open_webui/utils/plugin_cache.py` (+110 -0) 📝 `backend/open_webui/utils/tools.py` (+9 -5) </details> ### 📄 Description 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. ### Contributor License Agreement <!-- 🚨 DO NOT DELETE THE TEXT BELOW 🚨 Keep the "Contributor License Agreement" confirmation text intact. Deleting it will trigger the CLA-Bot to INVALIDATE your PR. Your PR will NOT be reviewed or merged until you check the box below confirming that you have read and agree to the terms of the CLA. --> - [X] By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. > [!NOTE] > Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-25 14:46:08 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#43059