fix: prevent unbounded memory growth in token refresh locks

use TTLCache instead of plain dict for _refresh_locks to auto-expire
locks for inactive sessions. prevents memory leak as sessions are
created and abandoned over time.

- max 10k concurrent sessions cached
- 1 hour TTL auto-expires unused locks
- uses existing cachetools dependency

Related to #708

Changed files
+5 -2
backend
src
backend
_internal
atproto
+5 -2
backend/src/backend/_internal/atproto/client.py
··· 6 6 from typing import Any 7 7 8 8 from atproto_oauth.models import OAuthSession 9 + from cachetools import TTLCache 9 10 10 11 from backend._internal import Session as AuthSession 11 12 from backend._internal import get_oauth_client, get_session, update_session_tokens 12 13 13 14 logger = logging.getLogger(__name__) 14 15 15 - # per-session locks for token refresh to prevent concurrent refresh races 16 - _refresh_locks: dict[str, asyncio.Lock] = {} 16 + # per-session locks for token refresh to prevent concurrent refresh races. 17 + # uses TTLCache to auto-expire locks for inactive sessions (1 hour TTL, max 10k sessions). 18 + # this prevents unbounded memory growth as sessions are created and abandoned. 19 + _refresh_locks: TTLCache[str, asyncio.Lock] = TTLCache(maxsize=10000, ttl=3600) 17 20 18 21 19 22 def reconstruct_oauth_session(oauth_data: dict[str, Any]) -> OAuthSession: