fix: serialize Tower migration validation
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-14 15:22:16 +02:00
parent c0943fe7d4
commit 7fa4f1fac9
5 changed files with 64 additions and 0 deletions
+1
View File
@@ -15,6 +15,7 @@
- Added a calm Latest state/Evolution flow to the map-first explorer, including period selection, metric comparison and added/removed/modified overlays where source identities support them.
- Added explicit operator provisioners for official Statbel Mol population snapshots (2021-2025) and Digitaal Vlaanderen historical land-use snapshots (1778, 1873 and 1969); no source is fetched during application startup.
- Preserved methodological honesty: partial statistical sectors are labelled area-weighted estimates, historical land-use identity changes are not fabricated and all source URLs, versions and processing limitations are persisted.
- Serialized Tower startup and migration-smoke validation by waiting for container health, preventing concurrent Alembic upgrades from racing on the same PostGIS schema.
## Sprint 186 Map-first Mol geographic explorer (2026-07-14)
@@ -248,3 +248,13 @@ def test_temporal_frontend_and_official_operator_contracts_exist() -> None:
assert "provision_mol_population_history.py" in dockerfile
assert "provision_mol_historical_landuse.py" in dockerfile
assert "fake" not in population.lower()
def test_tower_deploy_waits_for_startup_migration_before_live_smoke() -> None:
for relative_path in ("scripts/deploy_tower.ps1", "scripts/deploy_tower.sh"):
script = (ROOT / relative_path).read_text(encoding="utf-8")
wait_position = script.index("wait_for_geointel_health")
invocation_position = script.index("\nwait_for_geointel_health", wait_position)
smoke_position = script.index("LIVE_SMOKE_CONTAINER=geointel bash scripts/live_migration_smoke.sh")
assert "docker inspect --format" in script
assert invocation_position < smoke_position
+5
View File
@@ -7794,3 +7794,8 @@ Validation before live deployment:
Next:
- Run the complete readiness gate, deploy to Tower/PostGIS, provision the official snapshots and verify current/evolution selection end to end in the internal browser.
Live deployment correction:
- The first Tower rollout exposed a deployment race: all-in-one startup and `live_migration_smoke.sh` both began `alembic upgrade head` after PostgreSQL became reachable.
- Startup committed head `202607140001`; the concurrent smoke transaction rolled back on a duplicate first column. Database contents and the successful migration remained healthy.
- Both Tower deploy entry points now wait for the `geointel` container healthcheck, which includes completed startup migrations and backend readiness, before launching the independent migration smoke.
+24
View File
@@ -49,6 +49,30 @@ docker compose -f docker-compose.unraid.yml config >/dev/null
docker build --build-arg GEOINTEL_INSTALL_AI="$GEOINTEL_INSTALL_AI" -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest .
bash deploy/unraid/run-dockerman-container.sh
wait_for_geointel_health() {
local status=''
for attempt in $(seq 1 90); do
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' geointel 2>/dev/null || true)"
if [ "$status" = 'healthy' ]; then
echo "GeoIntel container is healthy after attempt $attempt."
return 0
fi
if [ "$status" = 'unhealthy' ] || [ "$status" = 'exited' ] || [ "$status" = 'dead' ]; then
echo "GeoIntel container entered terminal state: $status" >&2
docker logs --tail 120 geointel >&2 || true
return 1
fi
sleep 2
done
echo "GeoIntel container did not become healthy (last state: ${status:-missing})." >&2
docker logs --tail 120 geointel >&2 || true
return 1
}
# Container startup owns the migration. Waiting here prevents the validation
# smoke from racing a concurrent `alembic upgrade head` against the same DB.
wait_for_geointel_health
if [ -x scripts/live_migration_smoke.sh ]; then
LIVE_SMOKE_CONTAINER=geointel bash scripts/live_migration_smoke.sh
fi
+24
View File
@@ -51,6 +51,30 @@ docker compose -f docker-compose.unraid.yml config >/dev/null
docker build --build-arg GEOINTEL_INSTALL_AI="$GEOINTEL_INSTALL_AI" -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest .
bash deploy/unraid/run-dockerman-container.sh
wait_for_geointel_health() {
local status=''
for attempt in $(seq 1 90); do
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' geointel 2>/dev/null || true)"
if [[ "$status" == 'healthy' ]]; then
echo "GeoIntel container is healthy after attempt $attempt."
return 0
fi
if [[ "$status" == 'unhealthy' || "$status" == 'exited' || "$status" == 'dead' ]]; then
echo "GeoIntel container entered terminal state: $status" >&2
docker logs --tail 120 geointel >&2 || true
return 1
fi
sleep 2
done
echo "GeoIntel container did not become healthy (last state: ${status:-missing})." >&2
docker logs --tail 120 geointel >&2 || true
return 1
}
# Container startup owns the migration. Waiting here prevents the validation
# smoke from racing a concurrent `alembic upgrade head` against the same DB.
wait_for_geointel_health
if [[ -x scripts/live_migration_smoke.sh ]]; then
LIVE_SMOKE_CONTAINER=geointel bash scripts/live_migration_smoke.sh
fi