"""Wait for the database to accept connections before booting the app. For SQLite (current setup) this is effectively a no-op — the file is created on first connection. The script exists as scaffolding for a future move to Postgres, where the entrypoint must wait for the DB container to come up before `flask db upgrade` will succeed. Exit codes: 0 — DB is reachable 1 — gave up after MAX_WAIT_SECONDS """ import os import sys import time from sqlalchemy import create_engine, text from sqlalchemy.exc import OperationalError import config as app_config MAX_WAIT_SECONDS = int(os.environ.get('DB_WAIT_TIMEOUT', '30')) POLL_INTERVAL = 1.0 def main() -> int: uri = app_config.Config.SQLALCHEMY_DATABASE_URI # SQLite needs no wait — sqlite:/// URIs always succeed once the dir exists. if uri.startswith('sqlite:'): print(f'[wait_for_db] SQLite ({uri}) — no wait needed') return 0 engine = create_engine(uri, pool_pre_ping=True) deadline = time.monotonic() + MAX_WAIT_SECONDS attempt = 0 while True: attempt += 1 try: with engine.connect() as conn: conn.execute(text('SELECT 1')) print(f'[wait_for_db] connected after {attempt} attempt(s)') return 0 except OperationalError as e: if time.monotonic() >= deadline: print(f'[wait_for_db] gave up after {MAX_WAIT_SECONDS}s: {e}', file=sys.stderr) return 1 time.sleep(POLL_INTERVAL) if __name__ == '__main__': sys.exit(main())