Add no-op session cache when session cache is disabled
Use NoOpSessionCache in backend/app/main.py and dynamically switch cache implementation in backend/app/dependencies.py so disabled cache mode remains safe while get_session_cache always returns a valid object.
This commit is contained in:
@@ -667,6 +667,8 @@ A named 16-worker thread pool that is never actually used consumes OS thread res
|
|||||||
|
|
||||||
### Task 23 — Fix InMemorySessionCache instantiated when disabled
|
### Task 23 — Fix InMemorySessionCache instantiated when disabled
|
||||||
|
|
||||||
|
**Status:** Completed
|
||||||
|
|
||||||
**Severity:** Low
|
**Severity:** Low
|
||||||
|
|
||||||
**Where:**
|
**Where:**
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from app.repositories.protocols import SessionRepository
|
|||||||
from app.services.protocols import AuthService, JailService
|
from app.services.protocols import AuthService, JailService
|
||||||
from app.utils.constants import SESSION_COOKIE_NAME
|
from app.utils.constants import SESSION_COOKIE_NAME
|
||||||
from app.utils.runtime_state import RuntimeState
|
from app.utils.runtime_state import RuntimeState
|
||||||
from app.utils.session_cache import SessionCache
|
from app.utils.session_cache import InMemorySessionCache, NoOpSessionCache, SessionCache
|
||||||
|
|
||||||
log: structlog.stdlib.BoundLogger = structlog.get_logger()
|
log: structlog.stdlib.BoundLogger = structlog.get_logger()
|
||||||
|
|
||||||
@@ -79,6 +79,17 @@ def _session_cache_enabled(settings: Settings) -> bool:
|
|||||||
|
|
||||||
def _build_app_context(request: Request) -> ApplicationContext:
|
def _build_app_context(request: Request) -> ApplicationContext:
|
||||||
state = cast("AppState", request.app.state)
|
state = cast("AppState", request.app.state)
|
||||||
|
session_cache = getattr(state, "session_cache", None)
|
||||||
|
if session_cache is None:
|
||||||
|
session_cache = NoOpSessionCache()
|
||||||
|
state.session_cache = session_cache
|
||||||
|
elif _session_cache_enabled(state.settings) and isinstance(session_cache, NoOpSessionCache):
|
||||||
|
session_cache = InMemorySessionCache()
|
||||||
|
state.session_cache = session_cache
|
||||||
|
elif not _session_cache_enabled(state.settings) and not isinstance(session_cache, NoOpSessionCache):
|
||||||
|
session_cache = NoOpSessionCache()
|
||||||
|
state.session_cache = session_cache
|
||||||
|
|
||||||
return ApplicationContext(
|
return ApplicationContext(
|
||||||
settings=state.settings,
|
settings=state.settings,
|
||||||
http_session=getattr(state, "http_session", None),
|
http_session=getattr(state, "http_session", None),
|
||||||
@@ -88,7 +99,7 @@ def _build_app_context(request: Request) -> ApplicationContext:
|
|||||||
last_activation=getattr(state, "last_activation", None),
|
last_activation=getattr(state, "last_activation", None),
|
||||||
runtime_settings=getattr(state, "runtime_settings", None),
|
runtime_settings=getattr(state, "runtime_settings", None),
|
||||||
runtime_state=state.runtime_state,
|
runtime_state=state.runtime_state,
|
||||||
session_cache=getattr(state, "session_cache", None),
|
session_cache=session_cache,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ from app.routers import (
|
|||||||
from app.startup import startup_shared_resources
|
from app.startup import startup_shared_resources
|
||||||
from app.utils.fail2ban_client import Fail2BanConnectionError, Fail2BanProtocolError
|
from app.utils.fail2ban_client import Fail2BanConnectionError, Fail2BanProtocolError
|
||||||
from app.utils.runtime_state import ApplicationState, RuntimeState
|
from app.utils.runtime_state import ApplicationState, RuntimeState
|
||||||
from app.utils.session_cache import InMemorySessionCache
|
from app.utils.session_cache import InMemorySessionCache, NoOpSessionCache
|
||||||
from app.utils.setup_state import is_setup_complete_cached, set_setup_complete_cache
|
from app.utils.setup_state import is_setup_complete_cached, set_setup_complete_cache
|
||||||
|
|
||||||
log: structlog.stdlib.BoundLogger = structlog.get_logger()
|
log: structlog.stdlib.BoundLogger = structlog.get_logger()
|
||||||
@@ -290,7 +290,11 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
|||||||
# shared Starlette state bag itself does not hold mutable business state.
|
# shared Starlette state bag itself does not hold mutable business state.
|
||||||
app.state = ApplicationState(RuntimeState())
|
app.state = ApplicationState(RuntimeState())
|
||||||
app.state.settings = resolved_settings
|
app.state.settings = resolved_settings
|
||||||
app.state.session_cache = InMemorySessionCache()
|
app.state.session_cache = (
|
||||||
|
InMemorySessionCache()
|
||||||
|
if resolved_settings.session_cache_enabled and resolved_settings.session_cache_ttl_seconds > 0.0
|
||||||
|
else NoOpSessionCache()
|
||||||
|
)
|
||||||
set_setup_complete_cache(app, False)
|
set_setup_complete_cache(app, False)
|
||||||
|
|
||||||
# --- CORS ---
|
# --- CORS ---
|
||||||
|
|||||||
@@ -55,3 +55,19 @@ class InMemorySessionCache:
|
|||||||
|
|
||||||
def clear(self) -> None:
|
def clear(self) -> None:
|
||||||
self._entries.clear()
|
self._entries.clear()
|
||||||
|
|
||||||
|
|
||||||
|
class NoOpSessionCache:
|
||||||
|
"""A no-op session cache used when caching is disabled."""
|
||||||
|
|
||||||
|
def get(self, token: str) -> Session | None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set(self, token: str, session: Session, ttl_seconds: float) -> None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def invalidate(self, token: str) -> None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user