Fix: seed pre-tracking migrations to skip already-applied 02 and 03
Migration 02 and 03 were applied before the schema_migrations tracking table existed, so they had no record and the runner tried to re-run them, hitting non-idempotent TimescaleDB policy/trigger/cagg statements. seed_pre_tracking_migrations() checks for sentinel schema objects and inserts records for any migration that was clearly already applied: - 02: tracksolid.devices table exists - 03: position_history.altitude column exists Called immediately after ensure_tracking_table() on every startup. Safe on fresh databases (objects absent → nothing seeded → runs normally). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
63e555b822
commit
5d47eece6b
1 changed files with 40 additions and 0 deletions
|
|
@ -68,6 +68,45 @@ def ensure_tracking_table(conn):
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def seed_pre_tracking_migrations(conn):
|
||||||
|
"""
|
||||||
|
Retroactively mark migrations as applied if their schema objects already
|
||||||
|
exist. Required when the tracking table is introduced to a database that
|
||||||
|
was migrated before tracking existed — prevents re-running non-idempotent
|
||||||
|
statements (TimescaleDB policies, triggers, continuous aggregates).
|
||||||
|
"""
|
||||||
|
seeds = []
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# Migration 02: tracksolid.devices is the canonical sentinel table
|
||||||
|
cur.execute("""
|
||||||
|
SELECT 1 FROM information_schema.tables
|
||||||
|
WHERE table_schema = 'tracksolid' AND table_name = 'devices'
|
||||||
|
""")
|
||||||
|
if cur.fetchone():
|
||||||
|
seeds.append("02_tracksolid_full_schema_rev.sql")
|
||||||
|
|
||||||
|
# Migration 03: position_history.altitude column added in this migration
|
||||||
|
cur.execute("""
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'tracksolid'
|
||||||
|
AND table_name = 'position_history'
|
||||||
|
AND column_name = 'altitude'
|
||||||
|
""")
|
||||||
|
if cur.fetchone():
|
||||||
|
seeds.append("03_webhook_schema_migration.sql")
|
||||||
|
|
||||||
|
for filename in seeds:
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO tracksolid.schema_migrations (filename)
|
||||||
|
VALUES (%s) ON CONFLICT DO NOTHING
|
||||||
|
""", (filename,))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
if seeds:
|
||||||
|
print(f" Seeded pre-tracking migrations as applied: {', '.join(seeds)}")
|
||||||
|
|
||||||
|
|
||||||
def already_applied(conn, filename):
|
def already_applied(conn, filename):
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
|
|
@ -128,6 +167,7 @@ def main():
|
||||||
|
|
||||||
conn = get_conn()
|
conn = get_conn()
|
||||||
ensure_tracking_table(conn)
|
ensure_tracking_table(conn)
|
||||||
|
seed_pre_tracking_migrations(conn)
|
||||||
|
|
||||||
applied = skipped = 0
|
applied = skipped = 0
|
||||||
for sql_file in MIGRATIONS:
|
for sql_file in MIGRATIONS:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue