Document process-local auth session cache semantics

Clarify that dependencies.py session cache is process-local and not cluster-safe, and document the limitation in architecture docs.
This commit is contained in:
2026-04-07 20:42:31 +02:00
parent 3cc495dfce
commit effcc65e1b
3 changed files with 11 additions and 3 deletions

View File

@@ -657,6 +657,7 @@ BanGUI maintains its **own SQLite database** (separate from the fail2ban databas
- The frontend `AuthProvider` checks session validity on mount and redirects to `/login` if invalid. - The frontend `AuthProvider` checks session validity on mount and redirects to `/login` if invalid.
- The backend `dependencies.py` provides an `authenticated` dependency that validates the session cookie on every protected endpoint. - The backend `dependencies.py` provides an `authenticated` dependency that validates the session cookie on every protected endpoint.
- **Session validation cache** — validated session tokens are cached in memory for 10 seconds (`_session_cache` dict in `dependencies.py`) to avoid a SQLite round-trip on every request from the same browser. The cache is invalidated immediately on logout. - **Session validation cache** — validated session tokens are cached in memory for 10 seconds (`_session_cache` dict in `dependencies.py`) to avoid a SQLite round-trip on every request from the same browser. The cache is invalidated immediately on logout.
This cache is process-local and not safe for multi-worker or distributed deployments. A clustered deployment should replace `_session_cache` with a shared cache or remove it entirely.
- **Setup-completion flag** — once `is_setup_complete()` returns `True`, the result is stored in `app.state._setup_complete_cached`. The `SetupRedirectMiddleware` skips the DB query on all subsequent requests, removing 1 SQL query per request for the common post-setup case. - **Setup-completion flag** — once `is_setup_complete()` returns `True`, the result is stored in `app.state._setup_complete_cached`. The `SetupRedirectMiddleware` skips the DB query on all subsequent requests, removing 1 SQL query per request for the common post-setup case.
--- ---

View File

@@ -25,8 +25,8 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
- Fix: remove the unused `app.state.db` branch and always open/close a dedicated task-local connection, or intentionally add a shared DB connection to `app.state` and manage its lifecycle. - Fix: remove the unused `app.state.db` branch and always open/close a dedicated task-local connection, or intentionally add a shared DB connection to `app.state` and manage its lifecycle.
- Expected outcome: background jobs have predictable DB lifecycle, avoid hidden bugs from stale connection assumptions, and task code is simpler. - Expected outcome: background jobs have predictable DB lifecycle, avoid hidden bugs from stale connection assumptions, and task code is simpler.
- `backend/app/dependencies.py` contains an in-memory process-local session cache for auth tokens. This optimization is valid for a single-process server, but it is not cluster-safe for multi-worker or distributed deployments. - Status: **done** `backend/app/dependencies.py` contains an in-memory process-local session cache for auth tokens. This optimization is valid for a single-process server, but it is not cluster-safe for multi-worker or distributed deployments.
- Fix: either document the single-process limitation clearly, or replace `_session_cache` with an external shared cache (Redis/Memcached) or eliminate it if eventual cluster support is required. - Fix: document the single-process limitation clearly in code and project docs.
- Expected outcome: authentication behavior is consistent across deployment modes, and session invalidation works correctly in multi-worker setups. - Expected outcome: authentication behavior is consistent across deployment modes, and session invalidation works correctly in multi-worker setups.
- `backend/app/main.py` uses local imports inside `_lifespan()` to avoid circular dependencies, indicating that startup logic is tightly coupled with services. - `backend/app/main.py` uses local imports inside `_lifespan()` to avoid circular dependencies, indicating that startup logic is tightly coupled with services.

View File

@@ -46,6 +46,10 @@ _COOKIE_NAME = "bangui_session"
#: How long (seconds) a validated session token is served from the in-memory #: How long (seconds) a validated session token is served from the in-memory
#: cache without re-querying SQLite. Eliminates repeated DB lookups for the #: cache without re-querying SQLite. Eliminates repeated DB lookups for the
#: same token arriving in near-simultaneous parallel requests. #: same token arriving in near-simultaneous parallel requests.
#:
#: NOTE: this cache is process-local and is not cluster-safe. In multi-worker
#: or distributed deployments, each process maintains its own cache, so logout
#: invalidation and revocation may be delayed unless a shared cache is used.
_SESSION_CACHE_TTL: float = 10.0 _SESSION_CACHE_TTL: float = 10.0
#: ``token → (Session, cache_expiry_monotonic_time)`` #: ``token → (Session, cache_expiry_monotonic_time)``
@@ -56,6 +60,7 @@ def clear_session_cache() -> None:
"""Flush the entire in-memory session validation cache. """Flush the entire in-memory session validation cache.
Useful in tests to prevent stale state from leaking between test cases. Useful in tests to prevent stale state from leaking between test cases.
This only affects the current process.
""" """
_session_cache.clear() _session_cache.clear()
@@ -64,7 +69,9 @@ def invalidate_session_cache(token: str) -> None:
"""Evict *token* from the in-memory session cache. """Evict *token* from the in-memory session cache.
Must be called during logout so the revoked token is no longer served Must be called during logout so the revoked token is no longer served
from cache without a DB round-trip. from cache without a DB round-trip. This invalidation is local to the
current process; a clustered deployment would need a shared cache for
global invalidation.
Args: Args:
token: The session token to remove. token: The session token to remove.