Closes#121
WORKERS_PER_CORE, TIMEOUT, and GRACEFUL_TIMEOUT were consumed by the
old tiangolo/uvicorn-gunicorn-fastapi base image and are silently
ignored since switching to python:3.12-slim with an explicit uvicorn CMD.
Also applied the same removal to dev (ssh sba-db) and prod (ssh akamai)
docker-compose files directly. Added WEB_WORKERS=4 to prod to override
the Dockerfile default of 2.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
psycopg2-binary bundles its own libpq and does not need libpq-dev at
build time. curl is kept for the HEALTHCHECK.
Closes#118
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shell form CMD makes /bin/sh PID 1 — SIGTERM from docker stop goes to
the shell, not uvicorn, causing SIGKILL after the stop timeout instead
of graceful shutdown. Using CMD ["sh", "-c", "exec uvicorn ..."] lets
the shell expand $WEB_WORKERS then exec-replaces itself with uvicorn,
restoring correct signal delivery.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove :latest Docker tag to match Paper Dynasty convention — only
:version and :environment tags are pushed. Add WEB_WORKERS env var
to Dockerfile (default 2) so prod can override via docker-compose.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
numpy==1.26.4 has no Python 3.13 wheel and slim images have no build
toolchain, so the build would fail. python:3.12-slim matches the Python
version from the removed tiangolo base image.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The tiangolo/uvicorn-gunicorn-fastapi:python3.12 image was removed from
Docker Hub, breaking CI builds. Switches to official python:3.13-slim
with explicit uvicorn CMD. Fixes COPY path to match WORKDIR and adds
2 workers to replace the multi-worker gunicorn setup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds support for the 'dev' tag to trigger CI builds, pushing :dev Docker
tag for the dev environment. CalVer tags now also push :production alongside
:latest for future migration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Closes#110
The test was sending limit=999 which exceeds MAX_LIMIT (500), causing
FastAPI to return 422. Changed to limit=500, which is sufficient to
cover all seasons for any player.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace per-game update_standings() calls with pre-fetched dicts and
in-memory accumulation, then a single bulk_update at the end.
Reduces ~1,100+ queries for a full season to ~5 queries.
Closes#75
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes DATABASE_TYPE conditional entirely. PostgreSQL is now the only
supported backend. Moves PooledPostgresqlDatabase import to top-level
and raises RuntimeError at startup if POSTGRES_PASSWORD is unset,
preventing silent misconnection with misleading errors.
Closes#70
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Set timeout=5 so pool exhaustion surfaces as an error instead of hanging forever
- Set autoconnect=False to require explicit connection acquisition
- Add HTTP middleware in main.py to open/close connections per request
Closes#80
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes#78
Change CharField(max_length=20) to BigIntegerField to match the BIGINT
column created by the migration. Remove the str() workaround in
get_creator_by_discord_id() that was compensating for the type mismatch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After removing db.close() calls, 22 finally: blocks were left empty
(12 in custom_commands.py, 10 in help_commands.py), causing
IndentationError at import time. Removed the finally: clause entirely
since connection lifecycle is now handled by the middleware.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Match the discord bot's CI pattern — trigger on CalVer tag push
instead of branch push/PR. Removes auto-CalVer generation and
simplifies to a single build step.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>