Skip to content

driver-sql: boot schema-sync's MySQL widening ALTER is still unbounded (one year) and still swallows a metadata-lock timeout #9542

Description

@os-sam

Found while implementing #9354. Filed unassigned for triage; deliberately not fixed there, because the 2026-08-17 ruling scoped that card to the deferred-DDL flush path and widening it unasked would have re-litigated the ruling's minimality.

What #9354 changed, and where it stops

#9354 bounds lock_wait_timeout to 120s and raises an ADR-0112 refusal (DATABASE_ERROR / 500) when the MySQL widening ALTER TABLE … MODIFY COLUMN is blocked on a metadata lock — but only while flushDeferredSchemaDdl is running, i.e. only for operator-initiated os migrate apply.

The same two widening calls are reached from boot schema-sync through the same initObjects lines (packages/drivers/driver-sql/src/sql-driver.ts, the if (exists) await this.migrateMysqlDatetimeColumns(...) / migrateMysqlTimeColumns(...) pair). On that path the new runWideningAlters seam returns early and runs the statements through the pool, unbounded, exactly as before.

So on boot, against a table another session holds a metadata lock on:

  • the ALTER still inherits MySQL's default lock_wait_timeout of 31,536,000 seconds (one year);
  • nothing prints while it waits — boot appears to hang at schema-sync.

This is pinned as current, intended behaviour by sql-driver-deferred-ddl-lock-wait.test.ts ("leaves BOOT sync unbounded and swallowing — it is not the flush"), so it is a recorded gap rather than an unnoticed one.

Why it is not simply the same fix again

The swallow on the boot path is deliberate and documented — the widening's own doc comment states that correctness never depends on it having run, and that a migration must never take boot down. So the flush's answer (throw a loud refusal) is the wrong answer here: it would convert a lock contention into a failed boot.

The open question is therefore narrower than "apply the same fix":

  1. Should boot bound the wait at all (turning a year-long silent hang into a bounded wait plus the existing logger.warn), while still swallowing? That looks like a strict improvement — the warn already exists and would finally be reachable — but it changes boot timing behaviour.
  2. If so, is 120s the right bound for boot, or should boot be more patient than an operator at a prompt?

Suggested shape

Option 1 above, with the bound armed unconditionally and the refusal still gated on the flush: the runWideningAlters seam #9354 added already separates "bound the wait" from "escape the swallow", so this is a one-line change to the early-return condition plus a pin.

Related: #9354 (the ruling and the flush-path implementation) · #9350 (the metadata-lock measurement) · #3942 / #3994 (the widenings themselves).

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions