fix: add asyncio.Lock to get_browser() and deduplicate font-face blocks
All checks were successful
Build Docker Image / build (pull_request) Successful in 3m32s

Address two review findings from PR #94:

1. Race condition: concurrent requests could both launch Chromium when
   _browser is None. Wrap the init check in asyncio.Lock so only one
   coroutine creates the browser process.

2. Font duplication: the WOFF2 files are variable fonts covering all
   needed weights. Consolidate 5 @font-face blocks (3x Open Sans,
   2x Source Sans 3) into 2 using CSS font-weight range syntax,
   saving ~163KB of redundant base64 per render.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2026-03-13 08:28:58 -05:00
parent c262bb431e
commit 6ab50ba5f2
2 changed files with 19 additions and 33 deletions

View File

@ -9,6 +9,8 @@ from typing import Optional, List, Literal
import logging
import pydantic
from pandas import DataFrame
import asyncio as _asyncio
from playwright.async_api import async_playwright, Browser, Playwright
from ..card_creation import get_batter_card_data, get_pitcher_card_data
@ -37,6 +39,7 @@ from ..dependencies import oauth2_scheme, valid_token
_browser: Browser | None = None
_playwright: Playwright | None = None
_browser_lock = _asyncio.Lock()
async def get_browser() -> Browser:
@ -45,18 +48,22 @@ async def get_browser() -> Browser:
Reuses a single browser across all card renders, eliminating the ~1-1.5s
per-request launch/teardown overhead. Automatically reconnects if the
browser process has died.
Uses an asyncio.Lock to prevent concurrent requests from racing to
launch multiple Chromium processes.
"""
global _browser, _playwright
if _browser is None or not _browser.is_connected():
if _playwright is not None:
try:
await _playwright.stop()
except Exception:
pass
_playwright = await async_playwright().start()
_browser = await _playwright.chromium.launch(
args=["--no-sandbox", "--disable-dev-shm-usage"]
)
async with _browser_lock:
if _browser is None or not _browser.is_connected():
if _playwright is not None:
try:
await _playwright.stop()
except Exception:
pass
_playwright = await async_playwright().start()
_browser = await _playwright.chromium.launch(
args=["--no-sandbox", "--disable-dev-shm-usage"]
)
return _browser

File diff suppressed because one or more lines are too long