Extend seed sentinels to cover migrations 04 and 05

Containers share one DB — when ingest_movement applies 04, ingest_events
and webhook_receiver start later and find distance_m already renamed,
causing a spurious FATAL before the next restart catches the recorded row.

Added sentinels for all four migrations so any container self-heals
on first startup regardless of which container ran first:
  04 — trips.distance_km column exists
  05 — tracksolid.device_events table exists

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
David Kiania 2026-04-10 23:48:30 +03:00
parent 5d47eece6b
commit 5f1b32f1dc

View file

@ -71,40 +71,57 @@ def ensure_tracking_table(conn):
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).
exist. Checked on every startup safe to run repeatedly (ON CONFLICT DO
NOTHING). Prevents re-running non-idempotent statements when a second
container starts after another has already applied the migration, or when
the tracking table is introduced to a database migrated before it existed.
Sentinel objects per migration:
02 tracksolid.devices table exists
03 position_history.altitude column exists
04 trips.distance_km column exists (renamed from distance_m)
05 tracksolid.device_events table exists (new in 05)
"""
checks = [
(
"02_tracksolid_full_schema_rev.sql",
"SELECT 1 FROM information_schema.tables "
"WHERE table_schema='tracksolid' AND table_name='devices'",
),
(
"03_webhook_schema_migration.sql",
"SELECT 1 FROM information_schema.columns "
"WHERE table_schema='tracksolid' AND table_name='position_history' "
"AND column_name='altitude'",
),
(
"04_bug_fix_migration.sql",
"SELECT 1 FROM information_schema.columns "
"WHERE table_schema='tracksolid' AND table_name='trips' "
"AND column_name='distance_km'",
),
(
"05_enhancement_migration.sql",
"SELECT 1 FROM information_schema.tables "
"WHERE table_schema='tracksolid' AND table_name='device_events'",
),
]
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'
""")
for filename, query in checks:
cur.execute(query)
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,))
cur.execute(
"INSERT INTO tracksolid.schema_migrations (filename) "
"VALUES (%s) ON CONFLICT DO NOTHING",
(filename,),
)
seeds.append(filename)
conn.commit()
if seeds:
print(f" Seeded pre-tracking migrations as applied: {', '.join(seeds)}")
print(f" Seeded as applied: {', '.join(seeds)}")
def already_applied(conn, filename):