From d1d994c1a254902a2c19cbdad19acf54a592fa5f Mon Sep 17 00:00:00 2001 From: Tudor Date: Wed, 25 Mar 2026 10:57:01 +0000 Subject: [PATCH] fix(startup): stop re-migrating on every container restart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two issues caused the backend to drop and reimport school data on restart: 1. schema_version table was in the drop list inside run_full_migration(), so after any migration the breadcrumb was destroyed and the next restart would see no version → re-trigger migration 2. Schema version was set after migration, so a crash mid-migration left no version → infinite re-migration loop Fix: remove schema_version from the drop list, and set the version before running migration so crashes don't cause loops. Co-Authored-By: Claude Opus 4.6 --- backend/database.py | 12 ++++++------ backend/migration.py | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/backend/database.py b/backend/database.py index 75b86a5..57508e1 100644 --- a/backend/database.py +++ b/backend/database.py @@ -128,17 +128,17 @@ def check_and_migrate_if_needed(): print("Running full migration...") try: + # Set schema version BEFORE migration so a crash mid-migration + # doesn't cause an infinite re-migration loop on every restart. + init_db() + set_db_schema_version(SCHEMA_VERSION) + success = run_full_migration(geocode=False) if success: - # Ensure schema_version table exists before writing - init_db() - set_db_schema_version(SCHEMA_VERSION) - print(f"Migration complete. Schema version set to {SCHEMA_VERSION}") + print(f"Migration complete. Schema version {SCHEMA_VERSION}.") else: print("Warning: Migration completed but no data was imported.") - init_db() - set_db_schema_version(SCHEMA_VERSION) except Exception as e: print(f"FATAL: Migration failed: {e}") diff --git a/backend/migration.py b/backend/migration.py index b3f58d2..630155c 100644 --- a/backend/migration.py +++ b/backend/migration.py @@ -431,7 +431,8 @@ def run_full_migration(geocode: bool = False) -> bool: # Only drop the core KS2 tables — leave supplementary tables (ofsted, census, # finance, etc.) intact so a reimport doesn't wipe integrator-populated data. - ks2_tables = ["school_results", "schools", "schema_version"] + # schema_version is NOT dropped: it persists so restarts don't re-trigger migration. + ks2_tables = ["school_results", "schools"] print(f"Dropping core tables: {ks2_tables} ...") inspector = __import__("sqlalchemy").inspect(engine) existing = set(inspector.get_table_names())