Robustness: crash-safe migrations, stale-run sweep, optional prep tools; branded 404
- init_db applies each schema file with executescript (semicolons in triggers and string literals no longer break it) and records schema_version itself after each file, so a forgotten in-file bump can't re-run an ALTER and crash startup. Re-running is a no-op. - On startup, sweep any job_runs left in 'running' (killed by a restart) to 'interrupted' so the UI/history don't show a run stuck running forever. - prep-audio.sh skips loudgain and cue_file cleanly when they aren't installed (they aren't in the base image) instead of failing on a missing binary and logging errors; pipeline-status.sh routes syslog through a guard so a missing `logger` doesn't spew into the job log. - Add a branded 404 page (rendered to static HTML, no external runtime) via a custom exception handler that leaves all other responses, including the login redirect, untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+18
-2
@@ -1,17 +1,30 @@
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.exception_handlers import http_exception_handler
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from starlette.middleware.sessions import SessionMiddleware
|
||||
|
||||
from app.db import enable_beets_db_wal, init_db
|
||||
from app.db import enable_beets_db_wal, init_db, mark_interrupted_runs
|
||||
from app.routers import artist_casing, auth, credentials, dashboard, dedup, genres, health, import_, jobs, library, playlists
|
||||
from app.security.session import resolve_session_secret
|
||||
from app.services import scheduler_service
|
||||
from app.settings import settings
|
||||
|
||||
log = logging.getLogger("alembic")
|
||||
templates = Jinja2Templates(directory="app/templates")
|
||||
|
||||
|
||||
async def not_found_or_default(request: Request, exc: StarletteHTTPException):
|
||||
"""Render the branded 404 page for missing pages; leave every other
|
||||
HTTP exception (including the 303 login redirect raised by require_auth)
|
||||
to FastAPI's default handler so their status and headers are preserved."""
|
||||
if exc.status_code == 404:
|
||||
return templates.TemplateResponse(request, "404.html", {}, status_code=404)
|
||||
return await http_exception_handler(request, exc)
|
||||
|
||||
|
||||
def _warn_if_key_colocated_with_config() -> None:
|
||||
@@ -39,6 +52,7 @@ def _warn_if_key_colocated_with_config() -> None:
|
||||
async def lifespan(_app: FastAPI):
|
||||
_warn_if_key_colocated_with_config()
|
||||
init_db()
|
||||
mark_interrupted_runs()
|
||||
enable_beets_db_wal()
|
||||
|
||||
scheduler = scheduler_service.create_scheduler()
|
||||
@@ -53,6 +67,8 @@ async def lifespan(_app: FastAPI):
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI(title="alembic", lifespan=lifespan)
|
||||
|
||||
app.add_exception_handler(StarletteHTTPException, not_found_or_default)
|
||||
|
||||
app.add_middleware(SessionMiddleware, secret_key=resolve_session_secret())
|
||||
|
||||
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
||||
|
||||
Reference in New Issue
Block a user