T-05: Remove app.state mutation from _build_app_context

Move session cache initialization from per-request _build_app_context to
startup lifespan handler. The session cache type is now decided once at app
startup based on settings, making _build_app_context pure (read-only).

Changes:
- Move cache initialization logic to new _update_session_cache() in main.py
- Call _update_session_cache() during lifespan startup to initialize cache
- Remove three if/elif/elif branches mutating state.session_cache from _build_app_context
- Add cache swap logic to set_runtime_settings() in runtime_state.py to handle
  runtime settings changes (e.g., setup wizard updates)
- Keep app.state.session_cache initialization in create_app() for test compatibility

This ensures:
- _build_app_context is pure and doesn't mutate app state on each request
- Session cache configuration decisions are centralized at startup
- Settings changes during runtime (via setup wizard) also trigger cache swap
- Cache initialization logic is isolated in one place

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-25 18:23:08 +02:00
parent d467190eb1
commit e57d19fd76
3 changed files with 41 additions and 10 deletions

View File

@@ -24,6 +24,7 @@ from starlette.datastructures import State
from app.models.config import PendingRecovery
from app.models.server import ServerStatus
from app.utils.session_cache import InMemorySessionCache, NoOpSessionCache
if TYPE_CHECKING: # pragma: no cover
from app.config import Settings
@@ -118,10 +119,25 @@ def get_effective_settings(app: Any) -> Settings:
def set_runtime_settings(app: Any, settings: Settings) -> None:
"""Store the resolved runtime settings separately from bootstrap config."""
"""Store the resolved runtime settings separately from bootstrap config.
Also updates the session cache backend if the session cache configuration
has changed, replacing it with InMemorySessionCache or NoOpSessionCache
as appropriate.
Args:
app: The FastAPI application instance.
settings: The new effective settings.
"""
runtime_state = get_runtime_state(app)
runtime_state.runtime_settings = settings
# Update session cache if settings changed
cache_enabled = settings.session_cache_enabled and settings.session_cache_ttl_seconds > 0.0
new_cache = InMemorySessionCache() if cache_enabled else NoOpSessionCache()
app.state.session_cache = new_cache
log.debug("session_cache_updated", cache_type=type(new_cache).__name__)
def update_app_settings(app: Any, **overrides: Any) -> None:
"""Update the current effective settings immutably."""