+5
-2
backend/src/backend/_internal/atproto/client.py
+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: