the websocket migration runner disconnected and the agent cant tell whether the long-running ALTER finished
Fixes the uncertainty when a websocket-based migration runner disconnects during a long ALTER. It shows how to check the database directly for whether the ALTER is still running, finished, or never started, using pg_stat_activity and the information schema. Use when the runner is gone but the database may still be working.
TL;DR: The websocket dying does not kill the database query. Open a direct database connection, check pgstatactivity for the ALTER, and check the information schema for the expected change. Still running means wait, change present means done, absent and no backend means re-run - DDL is transactional so re-running is safe.
the websocket migration runner disconnected and the agent cant tell whether the long-running ALTER finished- Open a direct database connection that bypasses the websocket runner entirely, using psql or your usual client from a stable network path.
Expected: you get a working SQL prompt independent of the dead runner.
- Check whether the ALTER is still executing on the server.
SELECT pid, state, query, now() - query_start AS running_for
FROM pg_stat_activity
WHERE query ILIKE '%ALTER TABLE%YOUR_TABLE%';Expected: either a row showing the ALTER still running (with how long it has been going), or no rows, meaning it finished or never started.
- Check whether the schema change is actually present.
SELECT column_name, data_type FROM information_schema.columns
WHERE table_name = 'YOUR_TABLE' AND column_name = 'THE_NEW_COLUMN';Expected: the column is either there (ALTER finished) or not (ALTER never ran or rolled back).
- Decide based on the two checks. ALTER still running: wait and poll. Change present and no backend running: done, move on. Change absent and no backend running: re-run the ALTER, since Postgres DDL runs in a transaction and a dead session rolls back cleanly.
Expected: exactly one of the three outcomes, each with a clear next action.
- After re-running or confirming completion, verify the final schema matches the migration's intent and record the outcome outside the dead runner.
Expected: information_schema shows the intended final state.
Use this when
- A websocket, browser-based, or proxied migration runner disconnected mid-migration
- A long-running ALTER TABLE is unaccounted for
- The runner's logs are gone but the database is reachable directly
- You need to distinguish still-running from finished from never-started
Not for this skill when
- The database itself is unreachable - this skill assumes you can open a direct connection
- The migration was a multi-statement data copy rather than DDL - then verify row counts, not just schema
- Your database does not run DDL transactionally (MySQL implicitly commits around DDL) - a dead session can leave partial DDL, so inspect more carefully
- The runner has its own state store recording progress - check that first if it survived
Variant phrasings
- migration runner disconnected, did the ALTER TABLE finish
- websocket dropped during long alter, how to check
- agent lost connection to migration runner mid DDL
- cant tell if alter table completed after disconnect
Why it happens
A websocket disconnect only breaks the client transport. The database backend keeps running the query until it finishes or its own session dies. The runner was the only thing reporting progress, so its death looks like the migration's death. Postgres runs DDL inside a transaction, so there are only two stable outcomes: the change committed and is visible in the catalog, or the session died and everything rolled back. The information schema tells you which one happened.
Edge cases
- On MySQL, DDL is not transactional - a killed ALTER can leave a half-built table or a copied table behind. Check for temp tables and orphaned artifacts too.
- A very long ALTER on a huge table can run for hours. Do not re-run just because the runner died; the pgstatactivity check comes first.
- If the ALTER was waiting on a lock rather than executing, state will show idle in transaction or waiting. Find the lock holder before deciding to wait.
- Re-running an ALTER that actually did finish is harmless in Postgres (it errors cleanly on duplicate column), but check first anyway to keep the runbook honest.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_j9neSLNPao1o4y7tGLDHBw
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.