open-webui/backend/open_webui/routers
Classic298 d2e62db69b
fix: stop the sign-in rate limiter blocking the loop and leaking memory (#29977)
A slow Redis freezes the whole worker during sign-in, not just the user signing in. RateLimiter held a synchronous redis-py client and signin called is_limited inline from a coroutine, so every attempt did blocking round trips on the event-loop thread, with REDIS_SOCKET_TIMEOUT defaulting to None so nothing bounded the wait. Its Redis methods are now async and take the handle as their first argument, and both handlers pass request.app.state.redis, the async client the lifespan already creates. Building one in the limiter instead would pin its pooled connection to the first event loop that used it.

Without Redis, which is the default single-instance setup, the fallback store leaked. It was keyed by the rate-limit key and pruned a key's expired buckets only when that same key was checked again, so a login email never seen again was never reclaimed, and that email comes straight from an unauthenticated request body. It is now keyed by bucket, so one prune drops every key an expired bucket held, and it lives on the instance: pruning uses the per-instance num_buckets, so a shared store would let a limiter with a short window delete buckets a longer-windowed one still needs.

With a Redis costing a second per call, the widest event-loop tick gap drops from 2.010s to 0.010s and a concurrent request is answered at 0.05s instead of 2.05s, at no cost to the caller's own latency. Across 20,000 distinct keys the store goes from 40,000 entries and 6.4 MB, growing linearly, to a flat 1,004 entries and 100 KB. Rate-limiting decisions are unchanged across 700,000 randomised calls over 14 window, bucket and limit combinations, against a real Redis and the in-memory fallback alike, and sign-in still returns its first 429 on attempt 16.

Two behaviour changes worth naming. Pruning is now global rather than per key, so a wall clock that jumps forward past a full window and back forgets a hit it previously kept. The two limiters also stop sharing a store, which previously let a sign-in attempt with an IP-shaped email touch the token-exchange limiter's counters.
2026-09-13 20:28:41 -05:00
..
analytics.py refac 2026-06-29 01:38:41 -05:00
audio.py refac 2026-09-06 16:48:30 -04:00
auths.py fix: stop the sign-in rate limiter blocking the loop and leaking memory (#29977) 2026-09-13 20:28:41 -05:00
automations.py refac 2026-08-13 17:26:38 -06:00
calendar.py refac 2026-06-29 13:03:14 -05:00
channels.py fix: honor ENABLE_PROFILE_IMAGE_URL_FORWARDING for channel webhook profile images (#29889) 2026-09-12 16:06:34 -05:00
chats.py refac 2026-08-25 13:18:38 -04:00
configs.py refac 2026-09-07 12:15:20 -04:00
evaluations.py refac 2026-09-06 16:48:30 -04:00
files.py refac 2026-09-13 20:00:29 -04:00
folders.py fix: keep folder parent references acyclic (#28748) 2026-08-24 17:06:19 -04:00
functions.py fix: drop a deleted plugin's source from the content cache (#29983) 2026-09-13 20:21:40 -04:00
groups.py refac 2026-06-29 05:47:21 -05:00
images.py refac 2026-09-12 17:02:44 -04:00
knowledge.py refac 2026-09-09 17:09:53 -04:00
memories.py refac 2026-08-11 17:35:05 -06:00
models.py refac 2026-09-12 18:16:19 -04:00
notes.py refac 2026-08-25 13:18:38 -04:00
notifications.py refac 2026-07-27 19:39:36 -04:00
ollama.py fix: stop forwarding upstream Server and Date headers from the OpenAI and Ollama proxies (#29843) 2026-09-09 16:35:48 -04:00
openai.py fix: stop forwarding upstream Server and Date headers from the OpenAI and Ollama proxies (#29843) 2026-09-09 16:35:48 -04:00
pipelines.py perf: skip pipeline filter session setup when no filters exist (#29146) 2026-08-28 12:22:23 -04:00
prompts.py refac 2026-08-31 00:39:16 -04:00
retrieval.py fix: only log a reranking model change when the request carries one (#29922) 2026-09-12 16:04:14 -05:00
scim.py refac 2026-08-23 13:49:50 -04:00
skills.py perf: stop scanning every skill on each listing and chat turn (#28798) 2026-08-19 11:07:33 -07:00
tasks.py refac 2026-08-11 01:15:05 -06:00
terminals.py refac 2026-09-12 18:53:22 -04:00
tools.py fix: drop a deleted plugin's source from the content cache (#29983) 2026-09-13 20:21:40 -04:00
users.py refac 2026-09-07 14:46:52 -04:00
utils.py refac 2026-09-06 17:27:30 -04:00