WP-03: FastAPI Lifespan Hooks #90

Closed
opened 2026-03-13 04:37:05 +00:00 by cal · 2 comments
Owner

Description

Wire get_browser() and shutdown_browser() into FastAPI's lifespan so the browser warms up on startup and cleans up on shutdown.

Repo: database
Phase: 0 (Render Pipeline Optimization)
Dependencies: WP-02
Complexity: S

Current State

  • app/main.py line 54: plain FastAPI(...) constructor with no lifespan
  • Only middleware is the DB session handler (lines 97-105)

Implementation

  1. Add @asynccontextmanager lifespan function that calls get_browser() on startup and shutdown_browser() on shutdown
  2. Pass lifespan=lifespan to FastAPI() constructor
  3. Verify existing middleware is unaffected
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app: FastAPI):
    await get_browser()
    yield
    await shutdown_browser()

app = FastAPI(lifespan=lifespan)

Files

  • Modify: database/app/main.py — add lifespan hook, pass to FastAPI constructor
  • Modify: database/app/routers_v2/players.py — export get_browser/shutdown_browser (if not already importable)

Tests

  • Integration: browser is connected immediately after API startup (before any render request)
  • Integration: browser is closed after API shutdown (no orphan processes)
  • Integration: existing DB middleware still functions correctly
  • Integration: API health endpoint still responds

Acceptance Criteria

  1. Browser pre-warmed on startup — first render request has no cold-start penalty
  2. Clean shutdown — no orphan Chromium processes after API stop
  3. No regression in existing API behavior

Plan reference: docs/prd-evolution/PHASE0_PROJECT_PLAN.md WP-03

## Description Wire `get_browser()` and `shutdown_browser()` into FastAPI's lifespan so the browser warms up on startup and cleans up on shutdown. **Repo:** `database` **Phase:** 0 (Render Pipeline Optimization) **Dependencies:** WP-02 **Complexity:** S ## Current State - `app/main.py` line 54: plain `FastAPI(...)` constructor with no lifespan - Only middleware is the DB session handler (lines 97-105) ## Implementation 1. Add `@asynccontextmanager` lifespan function that calls `get_browser()` on startup and `shutdown_browser()` on shutdown 2. Pass `lifespan=lifespan` to `FastAPI()` constructor 3. Verify existing middleware is unaffected ```python from contextlib import asynccontextmanager @asynccontextmanager async def lifespan(app: FastAPI): await get_browser() yield await shutdown_browser() app = FastAPI(lifespan=lifespan) ``` ## Files - **Modify:** `database/app/main.py` — add lifespan hook, pass to FastAPI constructor - **Modify:** `database/app/routers_v2/players.py` — export `get_browser`/`shutdown_browser` (if not already importable) ## Tests - [ ] Integration: browser is connected immediately after API startup (before any render request) - [ ] Integration: browser is closed after API shutdown (no orphan processes) - [ ] Integration: existing DB middleware still functions correctly - [ ] Integration: API health endpoint still responds ## Acceptance Criteria 1. Browser pre-warmed on startup — first render request has no cold-start penalty 2. Clean shutdown — no orphan Chromium processes after API stop 3. No regression in existing API behavior **Plan reference:** `docs/prd-evolution/PHASE0_PROJECT_PLAN.md` WP-03
cal added this to the Card Evolution Phase 0 — Render Pipeline Optimization milestone 2026-03-13 04:37:37 +00:00
cal added the
evolution
phase-0
labels 2026-03-13 04:37:41 +00:00
Claude added the
ai-working
label 2026-03-13 10:31:19 +00:00
Claude added the
ai-pr-opened
label 2026-03-13 10:37:03 +00:00
Collaborator

PR #99 opened: #99

Approach: Added get_browser()/shutdown_browser() as a module-level Playwright singleton in players.py. The lifespan hook in main.py calls get_browser() on startup (pre-warming Chromium) and shutdown_browser() on exit. The card render block now reuses the singleton browser and closes only the page (in finally) rather than launching and closing a new browser per request.

PR #99 opened: https://git.manticorum.com/cal/paper-dynasty-database/pulls/99 **Approach:** Added `get_browser()`/`shutdown_browser()` as a module-level Playwright singleton in `players.py`. The lifespan hook in `main.py` calls `get_browser()` on startup (pre-warming Chromium) and `shutdown_browser()` on exit. The card render block now reuses the singleton browser and closes only the page (in `finally`) rather than launching and closing a new browser per request.
Claude removed the
ai-working
label 2026-03-13 10:37:14 +00:00
Author
Owner

Completed. lifespan() context manager added to app/main.py — calls shutdown_browser() on API shutdown for clean Chromium teardown. PR #99 merged via next-release.

**Completed.** `lifespan()` context manager added to `app/main.py` — calls `shutdown_browser()` on API shutdown for clean Chromium teardown. PR #99 merged via next-release.
cal closed this issue 2026-03-16 19:48:28 +00:00
Sign in to join this conversation.
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/paper-dynasty-database#90
No description provided.