Black Friday salejusqu'à 60% de réduction
  • 60% de réduction sur votre première année d'abonnement annuel
  • 45% de réduction sur les licences à vie
Se termine dans
Profiter de l'offre

The Database Moved. One Old Client Did Not — NovaCommerce 3

A 26-minute database cutover looked complete until a legacy panel wrote to the old copy. The lesson is writer control, reconciliation and honest recovery.

Auteur

Anichur Rahaman

il y a 1 mois5 min de lecture285 vues
The Database Moved. One Old Client Did Not — NovaCommerce 3

At 22:59 on 5 October 2026, the planned database window ended. The site was back after 26 minutes. At 23:24 the team found a legacy admin panel still writing to the old database. The application had moved; its complete writer population had not.

NovaCommerce is an anonymised course-and-exam platform. Part 3 preserves the existing September–October project record and corrects the general guidance around it. These historical counts are not newly audited production measurements or StoreConsole benchmarks.

A smaller pair answered a different risk

The old managed MySQL was one 8 vCPU/32 GB node without a standby. The new historical setup was MySQL 8.4 Standard, 4 vCPU/16 GB per node, primary plus standby, for about 11 GB of data. This addressed a single-node failure path; it did not prove zero data loss, zero failover delay or regional recovery.

The roughly $389/month pair was a historical case budget, not a current offer. DigitalOcean now documents Standard Edition restrictions from 15 October 2026 for newly eligible accounts and 30 November for all accounts. Verify account, plan and standby eligibility before reproducing the setup. A standby follows data changes, including accidental deletion; it is not a backup.

The cutover passed some checks and missed a writer

The record describes maintenance routing at 22:33, draining queues, stopping scheduled work, observing no writes for 30 seconds, a roughly ten-minute copy, validation and new application images before 22:59. A quiet observation window is not a fence: a forgotten client can write later. Inventory web, workers, schedulers, callbacks, imports and external panels, then block all old writes before taking a consistent copy.

The case reported matching table/row totals, subsequent table-content checks and a detailed comparison of a large results table. Preserve evidence of what was compared, at which snapshot and with which method. Counts alone do not prove equal contents, and post-cutover comparisons need an explicit reconciliation boundary. Check roles, schema, routines/events where used, character sets and real answer-save/read flows too. Standard mysqldump is not a parallel-dump engine; do not treat an undocumented multi-stream wrapper as a reproducible consistency recipe.

Historical observationRecorded valueWhat it does not prove
Copy totals341 tables; 18,727,244 rowsEqual counts ≠ equal business state
Largest results comparisonAbout 2.76 million rowsScope/method must be retained
First four minutes after reopeningAbout 2,900 requests; 0 5xxNot every later flow or writer
Late legacy writes48 =44 merged +4 retainedNot a generic merge policy
Web-only connection estimate10 ×80 =800Read/write, worker and overlap excluded

Forty-eight late rows changed the rollback story

The legacy panel added 48 rows to the old side. The historical repair merged 44 and kept four newer destination versions, then moved that panel and changed old access credentials. That 44+4=48 accounting describes this incident, not a safe generic “latest timestamp wins” algorithm. Clocks, deletes, dependent rows and concurrent edits require business-aware reconciliation and an audit trail.

Stop missed writers and terminate or otherwise fence existing connections; changing a password alone may not close an already authenticated session. Verify old writes are denied. The old cluster was reportedly kept frozen for 48 hours. Once the new side accepts work, that old copy is recovery material, not an immediately current rollback destination. Returning to it without reconciling new answers can lose accepted work. Retention should follow tested recovery and obligations, not a universal 48-hour rule.

Database cutover evidence map: inventory clients, fence old writers, copy consistently, validate, switch one writer and reconcile late rows before recovery.
The missed legacy panel is a writer-control lesson. The recorded 26-minute window is not a reusable migration-time promise.

A read replica is useful only with a freshness contract

The case used the standby and primary as read hosts, with primary-only writes and primary reads for the worker. A supported standby-read endpoint can reuse paid capacity, but it also shares failure/recovery resources. Check provider support, lag and failure behaviour; a dedicated reader is not always wasteful.

Laravel sticky=true routes later reads to the write connection after a write within the same request. It does not alone protect the next request or every user session. Cross-request freshness needs an explicit tested mechanism or primary reads for authoritative answers. Multiple read hosts do not establish a universal two-second failover or safe replay of arbitrary queries. Test connection failure separately from a query that already executed.

The old 10 nodes ×80 PHP-FPM children=800 estimate counts only one connection per child. A child may open read and write connections; two per child gives 1,600 before the worker, admin sessions or rolling overlap, against the historical 1,601 limit. Budget every connection source and node generation. A connection ceiling is not a throughput guarantee.

Keep vector work separate without promising total isolation

A separate PostgreSQL 17/pgvector instance held AI embeddings, historically 2 vCPU/4 GB. A 1 vCPU/2 GB trial was reversed when its workload needed more. Separate instances give CPU/memory budgets; shared application pools, network or providers can still couple failures. This is a workload choice, not a claim that every MySQL offering lacks vector capabilities.

On the 7 October exam evening, the record reports MySQL CPU max 24.5%, average 13.4%, at most five running queries and zero observed lock waits. These support the narrower conclusion that the measured window did not saturate those signals. They do not prove a 450 requests/s ceiling or sixfold capacity: query mix, write contention, I/O and failover change the result.

Keep least-privilege application credentials separate from migration rights, restrict database access and test restoring backups with application checks and measured recovery objectives. A configured standby, a successful copy and a successful restore are three different pieces of evidence. Part 4 follows the queues and worker that still connect this fleet.

Series

Primary references

Reviewed 6 November 2026. Anichur Rahaman, StoreConsole founder. Case figures and prices remain historical; current primary sources support the technical qualifications.

À propos de l'auteur

Anichur Rahaman

Continuer la lecture