Database Migrations in Production
The API container applies alembic upgrade head at every start. An upgrade of Fonrex is therefore an upgrade of the schema: prepare it.
Upgrade procedure
-
Back up the database:
docker compose exec -T db pg_dump -U fonrex -d fonrex -Fc > fonrex-$(date +%F).dump -
Update the code:
git pull. -
Migrate alone (optional, to see the migrations run before the API starts):
docker compose --profile migrate build fonrex-migratedocker compose --profile migrate run --rm fonrex-migrate -
Start the new version:
docker compose up -d --build. -
Check:
docker compose logs fonrex-apishows the migrations applied, thencurl http://localhost:5000/healthand a few requests with your key. A database left behind the code makes its routes answer503.
Rolling back
Restore the backup taken in step 1 with the previous version of the code (see Docker Compose). Prefer it to alembic downgrade: some downgrades cannot give back what the upgrade removed (migration 008 drops tables; migration 014 keeps one bar per instrument and date when going back).
Notable migrations
| Migration | What to know |
|---|---|
| 014 — prices per listing | Rebuilds prices_eod with one series per listing and re-dates the existing bars to their trading session. Runs by itself; nothing is downloaded again. If a series looks wrong afterwards: POST /historical/ingest?ticker=<ticker>&force_refresh=true |
| 015 — dividend yields as ratios | Converts stored dividend yields from percentages to ratios |
| 016 — adjustment of price series | Creates price_series_adjustments. Prices are not touched: each series stored before is fetched again in full at its next ingestion, with the traded close in close and the dividend-adjusted close in adj_close. To do it at once: docker compose exec fonrex-api python scripts/ingest_all.py --force |
The full list is in Schema migrations.
Testing migrations
The database tests apply the migrations to a real TimescaleDB, on existing data, down and up again:
make test-db # throwaway container of the image of docker-compose.yml, port 54329
To run them against your own server (a temporary database is created and dropped):
FONREX_TEST_DATABASE_URL=postgresql://fonrex:<password>@localhost:5432/fonrex \
pytest tests/test_timescale_integration.py