From 351fc0b2a332e136a2112cf1d5fdb4ea79aa1771 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Fri, 9 Oct 2026 18:10:56 +0000 Subject: [PATCH] Fix synchronization race in upgrade tests --- docs/upgrade-testing.md | 5 +++++ scripts/test-upgrade.sh | 25 ++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/upgrade-testing.md b/docs/upgrade-testing.md index 75acdc5a..f969dd47 100644 --- a/docs/upgrade-testing.md +++ b/docs/upgrade-testing.md @@ -59,6 +59,11 @@ We never downgrade. Downgrade scripts are not needed. | Monitoring | `df.status()`, `df.result()`, `df.list_instances()`, `df.instance_info()` | | In-flight work | Orchestrations started before `.so` swap complete after swap (except across an activity-input change — see #129) | +The current-satellite/legacy-control overlap check waits separately for local +workflow completion and provider completion. `df.wait_for_completion()` (or +`df.await_instance()`) observes `df.instances`; it can return before duroxide +commits its terminal orchestration state. + **What it catches:** - SQL queries in Rust code referencing columns/constraints that don't exist in the old schema - Changed function signatures that conflict with old SQL wrappers diff --git a/scripts/test-upgrade.sh b/scripts/test-upgrade.sh index a8941bc3..28ddd2f5 100755 --- a/scripts/test-upgrade.sh +++ b/scripts/test-upgrade.sh @@ -1081,9 +1081,28 @@ test_b1_mixed_version_multidb() ( (SELECT oid::text FROM pg_database WHERE datname = current_database()) || '-' || replace(id::text, '-', '') || '-${satellite_id}' FROM df._installation WHERE singleton;") || return 1 [[ "$satellite_engine_id" =~ ^pgdf-[0-9]+-[0-9a-f]{32}-${satellite_id}$ ]] || return 1 - assert_sql_equals "SELECT EXISTS (SELECT 1 FROM duroxide.get_instance_info('${control_id}') WHERE status = 'Completed') - AND EXISTS (SELECT 1 FROM duroxide.get_instance_info('${satellite_engine_id}') WHERE status = 'Completed') - AND (SELECT extversion FROM pg_extension WHERE extname = 'pg_durable') = '${B1_VERSION}';" "t" || return 1 + # df.wait_for_completion() observes df.instances before the provider commits + # its terminal orchestration state. + "${sql_client[@]}" -d "$control_db" -c "DO \$\$ + DECLARE + control_status TEXT; + satellite_status TEXT; + deadline TIMESTAMPTZ := clock_timestamp() + interval '5 seconds'; + BEGIN + LOOP + SELECT status INTO control_status FROM duroxide.get_instance_info('${control_id}'); + SELECT status INTO satellite_status FROM duroxide.get_instance_info('${satellite_engine_id}'); + IF control_status = 'Completed' AND satellite_status = 'Completed' THEN + RETURN; + END IF; + EXIT WHEN clock_timestamp() >= deadline; + PERFORM pg_sleep(0.01); + END LOOP; + RAISE EXCEPTION 'Timed out waiting for provider completion: control % (status %), satellite % (status %)', + '${control_id}', coalesce(control_status, 'missing'), + '${satellite_engine_id}', coalesce(satellite_status, 'missing'); + END \$\$;" || return 1 + assert_sql_equals "SELECT extversion FROM pg_extension WHERE extname = 'pg_durable';" "$B1_VERSION" || return 1 case "$B1_VERSION" in 0.2.[2-8]) assert_sql_equals "SELECT to_regclass('df._installation') IS NULL;" "t" || return 1