open-webui/backend/open_webui/utils
Classic298 4caf255389
fix: refresh an expiring OAuth token once across workers and replicas (#30450)
#30426 stopped concurrent requests from refreshing the same OAuth session twice, but its lock only lives inside one process. With several uvicorn workers or replicas, two requests on different workers still send the same refresh token, a rotating provider rejects the second with invalid_grant, and the session gets deleted, so the user's OAuth session is logged out again.

When Redis is configured, which multi-worker and multi-replica deployments require, the refresh now takes a Redis lock per session instead of the in-process one. Single-process deployments without Redis keep the in-process lock. The waiter re-reads the session inside the lock as before and uses the token that was just stored.

It uses redis-py's own async lock because the existing RedisLock is synchronous and never waits. The Sentinel proxy now passes `lock` through unwrapped like `pipeline` and `pubsub`; otherwise it returned a coroutine and every refresh behind Sentinel would fail.

Tested with separate OS processes on one sqlite DB, a real Redis and a rotating mock provider: 2 and 5 processes (and 5 processes x 3 requests) now cause 1 refresh, every caller gets the new token and the session is kept (before: one refresh per process, session deleted every run). Single refresh, failed refresh, valid token and the single-process path without Redis are unchanged.

Follow-up to #30426, refs #30416
2026-09-23 23:33:09 -04:00
..
access_control chore: format 2026-09-21 11:35:30 -04:00
images perf: build debug log messages lazily so disabled debug logs cost nothing (#27834) 2026-07-31 19:09:01 -05:00
mcp refac 2026-09-12 14:57:22 -04:00
telemetry refac(telemetry): drop deprecated semconv SpanAttributes subclass (#25784) 2026-06-29 02:05:34 -05:00
actions.py fix: enforce action availability and model access on the chat action route (#27243) 2026-07-23 12:23:05 -04:00
anthropic.py fix: drop thinking blocks when converting Anthropic Messages requests to Chat Completions (#29849) 2026-09-12 15:56:59 -05:00
asgi_middleware.py refac 2026-08-24 18:29:36 -04:00
ask_user.py fix: a rejected ask_user call ending the turn with no reply (#29252) 2026-08-31 00:17:21 -04:00
audit.py perf: build debug log messages lazily so disabled debug logs cost nothing (#27834) 2026-07-31 19:09:01 -05:00
auth.py refac 2026-09-19 17:54:09 -04:00
automations.py refac 2026-09-21 08:59:39 -04:00
calendar.py fix: correct recurrence rule parsing for schedules and calendar events (#29262) 2026-09-21 08:44:13 -04:00
channels.py refac 2026-03-17 17:58:01 -05:00
chat.py fix: keep the model system prompt on Ollama tool-call follow-ups (#30375) 2026-09-22 16:47:20 -04:00
chat_fork.py refac 2026-07-23 02:54:56 -04:00
chat_id.py refac 2026-07-26 21:12:14 -04:00
chat_variables.py perf: stabilize the model registry signature across workers (#29264) 2026-08-30 16:12:31 -04:00
code_interpreter.py refac 2026-07-31 17:41:14 -04:00
context_compaction.py refac 2026-08-23 13:36:53 -04:00
embeddings.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
files.py refac(images): request an unencoded body when fetching remote chat images (#29623) 2026-09-21 08:53:06 -04:00
filter.py refac 2026-08-31 01:29:36 -04:00
groups.py refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
headers.py refac 2026-09-12 15:41:57 -04:00
json_codec.py perf: write task payloads to Redis as bytes (#28833) 2026-08-20 12:58:52 -07:00
json_response.py perf: optional orjson JSON codec behind ENABLE_ORJSON (#27583) 2026-07-27 03:45:37 -04:00
logger.py perf: stop formatting every exported log record twice under OTEL log export (#27840) 2026-08-10 23:13:52 -06:00
memory.py fix: stop the background memory review when memory is switched off (#30309) 2026-09-21 11:22:21 -04:00
middleware.py fix: stop KeyError 'model' traceback on every new chat from initial title generation (#30356) 2026-09-22 11:35:14 -04:00
misc.py fix: treat SVG uploads as documents instead of vision images (#30102) 2026-09-17 17:40:07 -04:00
model_ids.py refac 2026-07-26 23:09:22 -04:00
models.py fix: stop asking for chat variables a model's system prompt no longer declares (#30173) 2026-09-21 10:23:21 -04:00
notifications.py fix: sanitize user-typed notification target ids the same way generated ones are (#29947) 2026-09-12 13:50:19 -05:00
oauth.py fix: refresh an expiring OAuth token once across workers and replicas (#30450) 2026-09-23 23:33:09 -04:00
payload.py refac 2026-08-16 22:56:19 -07:00
plugin.py perf: build info log messages lazily so raising the log level actually saves work (#27837) 2026-08-02 15:39:10 -05:00
rate_limit.py fix: stop the sign-in rate limiter blocking the loop and leaking memory (#29977) 2026-09-13 20:28:41 -05:00
recurrence.py fix: evaluate automation schedules on Windows with PostgreSQL (#30424) 2026-09-23 08:47:04 -05:00
redis.py fix: refresh an expiring OAuth token once across workers and replicas (#30450) 2026-09-23 23:33:09 -04:00
response.py refac 2026-08-17 00:57:57 -07:00
sanitize.py refac 2026-03-17 17:58:01 -05:00
security_headers.py refac 2026-08-24 18:29:36 -04:00
session_pool.py fix: long streamed lines no longer abort the response (#28114) 2026-08-25 12:16:37 -04:00
skills.py chore: format 2026-09-21 11:35:30 -04:00
subagents.py chore: format 2026-08-25 16:53:53 -04:00
task.py refac 2026-06-19 00:16:06 +02:00
terminals.py refac 2026-09-19 17:33:41 -04:00
timers.py refac: check the timer owner's role before running a due timer (#30220) 2026-09-21 10:46:48 -04:00
tool_approval.py chore: format 2026-08-25 16:53:53 -04:00
tools.py fix: stop injecting memories and memory tools when memory is switched off (#30228) 2026-09-21 01:00:08 -04:00
validate.py refac 2026-09-15 22:47:03 -04:00
valves.py refac 2026-07-31 17:41:14 -04:00
webhook.py perf: build debug log messages lazily so disabled debug logs cost nothing (#27834) 2026-07-31 19:09:01 -05:00