Expand-migrate-contract is correct and takes three releases, which is two weeks on a fortnightly cadence — and occasionally the change cannot wait that long.
-- a view is the indirection that makes one release possible
CREATE TABLE orders_v2 LIKE orders;
ALTER TABLE orders_v2 CHANGE customer_ref customer_id BIGINT;
-- backfill, then, in one transaction:
RENAME TABLE orders TO orders_old, orders_v2 TO orders;
-- RENAME of several tables is atomic. this is the whole trick.
A multi-table RENAME is atomic in MySQL, so there is no moment where the name resolves to nothing — which is what makes this a swap rather than a gap. The cost is that writes arriving during the backfill have to be captured, by a trigger or by dual-writing, and the trigger is the part that goes wrong. It is the right tool for a table that is read constantly and written rarely, and the wrong one otherwise.