tracksolid_timescale_grafan.../run_migrations.py
David Kiania 4a31de30b1 Add db_migrate init service to auto-run SQL schema on deploy
- New run_migrations.py: executes 02_*.sql and 03_*.sql in order
- New db_migrate service: runs once before all other services start
- All services now depend on db_migrate (service_completed_successfully)
- Tolerates re-deploy: catches errors from already-existing objects

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 17:02:09 +03:00

66 lines
1.7 KiB
Python

"""
run_migrations.py — Idempotent SQL migration runner for Docker init service.
Executes each .sql migration file in order using psycopg2.
Tolerates re-run errors (e.g. "policy already exists") so deploys are safe.
"""
import os
import sys
import psycopg2
DATABASE_URL = os.environ["DATABASE_URL"]
MIGRATIONS = [
"02_tracksolid_full_schema_rev.sql",
"03_webhook_schema_migration.sql",
]
def run_file(conn, path, filename):
"""Execute a SQL file. Returns True on success, False on error."""
with open(path) as f:
sql = f.read()
try:
with conn.cursor() as cur:
cur.execute(sql)
print(f" OK: {filename}")
return True
except psycopg2.Error as e:
msg = (e.pgerror or str(e)).strip().split("\n")[0]
print(f" WARN: {filename}: {msg}")
# Connection is now in error state — must reset
conn.close()
return False
def main():
print("=== Database Migration Runner ===")
conn = psycopg2.connect(DATABASE_URL)
conn.autocommit = True
warnings = 0
for sql_file in MIGRATIONS:
path = os.path.join("/app", sql_file)
if not os.path.exists(path):
print(f" SKIP: {sql_file} (not found)")
continue
print(f"Running {sql_file}...")
ok = run_file(conn, path, sql_file)
if not ok:
warnings += 1
# Reconnect for the next file
conn = psycopg2.connect(DATABASE_URL)
conn.autocommit = True
conn.close()
if warnings:
print(f"Completed with {warnings} warning(s) (expected on re-deploy).")
else:
print("All migrations applied cleanly.")
sys.exit(0)
if __name__ == "__main__":
main()