Cloudflare D1
Migrations
Schema
Deploy
SQLite

Migrazioni in D1: come modificare lo schema di versione e cosa succede quando va storto

Il sistema di migrazione di D1 è semplice e funziona bene, finché non è necessario annullare una migrazione già eseguita in produzione e scoprire che non è previsto alcun rollback nativo.

Migrazioni in D1: come modificare lo schema di versione e cosa succede quando va storto

Il sistema di migrazione di D1 è stato progettato per semplicità, non per sicurezza. File .sql numerati in sequenza, applicati tramite wrangler d1 migrations apply, senza rollback. Rispetto a strumenti come Flyway, Liquibase o persino il sistema di migrazione Rails, che consentono migrazioni verso il basso e controllo delle versioni bidirezionale, D1 offre un flusso unidirezionale. Funziona bene quando la migrazione è ben testata e procede esattamente come previsto. In caso contrario, le opzioni di ripristino sono limitate e devono essere preparate prima che si verifichi il problema, non durante.

Come funziona il sistema di migrazione di D1

wrangler d1 migrations create NOME crea un file .sql numerato nella directory del progetto migrations/. Il numero è sequenziale e determina l'ordine di applicazione: 0001_create_users.sql, 0002_add_status_column.sql e così via. wrangler tiene traccia di quali migrazioni sono già state applicate in una tabella interna chiamata D1_MIGRATIONS all'interno del database stesso.

wrangler d1 migrations apply NOME_DO_BANCO applica tutte le migrazioni in sospeso in ordine. wrangler d1 migrations list --remote mostra lo stato attuale: quali sono stati applicati e quali sono in sospeso. Questo flusso è sufficiente per la maggior parte dei casi.

Il limite strutturale: non esiste il --rollback. Una migrazione applicata a un database D1 non prevede l'annullamento automatico. Se la migrazione 0015 ha introdotto un bug nello schema ed è necessario ripristinarlo, sono disponibili due opzioni. Il primo è scrivere la migrazione 0016 che annulla manualmente ciò che ha fatto 0015: possibile per operazioni non distruttive come l'aggiunta di una colonna, ma impossibile per operazioni che eliminano dati, come DROP COLUMN o DROP TABLE. Il secondo consiste nell'utilizzare Time Travel di D1 per ripristinare il database a un punto precedente alla migrazione, disponibile per piani a pagamento con una finestra di 30 giorni.

Il problema della coerenza dello schema al limite

La replica D1 crea un rischio di implementazione che le banche tradizionali non hanno: la migrazione può avvenire sul primario mentre le repliche caricano ancora il vecchio schema. Un lavoratore che legge da una replica obsoleta eseguirà query su uno schema diverso da quello previsto.

Lo scenario concreto: aggiungi la colonna status alla tabella orders con la migrazione 0020. La migrazione viene eseguita sul server primario. Allo stesso tempo, schieri il Lavoratore aggiornato che fa SELECT status FROM orders. Una richiesta che raggiunge una replica che non ha ancora ricevuto la migrazione fallirà con un errore di colonna sconosciuta, anche se la distribuzione è andata a buon fine e il primario ha già lo schema corretto.

L'intervallo di propagazione può raggiungere i 60 secondi. La soluzione è separare la distribuzione della migrazione dalla distribuzione del codice. Il flusso corretto: applicare la migrazione, attendere esplicitamente per almeno 60 secondi, quindi distribuire la nuova versione del Worker. Questa attesa deve essere incorporata nella pipeline CI/CD: il wrangler deploy non ha un flag di "attesa per la propagazione dello schema", quindi è necessario creare questo ritardo manualmente. Nella stragrande maggioranza dei casi è sufficiente un sleep 60 tra le due fasi della pipeline.

Playbook per migrazioni sicure in produzione

Prima di applicare qualsiasi migrazione a un database di produzione, esportare un dump completo: wrangler d1 export --remote --database NOME_DO_BANCO --output backup-$(date +%Y%m%d-%H%M).sql. Questo file è il percorso di ripristino manuale nel caso in cui qualcosa vada storto e Time Travel non sia disponibile o non sia sufficiente.

Testare la migrazione su un database di staging con dati di volume equivalente alla produzione. Una migrazione eseguita in 50 ms su una tabella con 1.000 righe può richiedere 20 secondi su una tabella con 5 milioni di righe e durante questi 20 secondi il database potrebbe non essere disponibile per le query che dipendono dalla modifica della tabella. D1 non dispone di reindicizzazione in background come PostgreSQL con CREATE INDEX CONCURRENTLY.

Per le modifiche allo schema che non richiedono tempi di inattività, utilizzare il modello di distribuzione a fasi. Per rinominare una colonna, elabora il processo in passaggi indipendenti: innanzitutto aggiungi la nuova colonna come nullable; in secondo luogo, distribuisci il codice che scrivi in ​​entrambe le colonne (vecchia e nuova); terzo, un lavoro di recupero che copia i dati dalla vecchia alla nuova colonna nei record esistenti; quarto, aggiorna il codice per leggere solo dalla nuova colonna; quinto, rimuovere la vecchia colonna in una migrazione successiva. La combinazione di tutti questi passaggi in un'unica migrazione crea una finestra di incoerenza e non consente il rollback parziale.

Testare le migrazioni localmente prima di metterle in produzione

wrangler dev --local crea un vero file SQLite in .wrangler/state/v3/d1/. Puoi applicare le migrazioni su questo file con wrangler d1 migrations apply NOME --local, ispezionarlo direttamente con il client sqlite3 ed eseguire EXPLAIN QUERY PLAN sulle query per verificare che gli indici siano utilizzati correttamente prima di qualsiasi distribuzione.

Il divario tra locale e remoto è la replica. L'ambiente locale è un'istanza SQLite pura senza il livello primario e le repliche: eventuali problemi di coerenza non verranno visualizzati nei test locali. Per coprire questa lacuna, crea una banca di staging D1 separata nel tuo account Cloudflare, applica prima le migrazioni lì e convalida il comportamento con dati che si avvicinano al volume di produzione.

Il viaggio nel tempo è il piano B quando tutto il resto fallisce. wrangler d1 time-travel restore --timestamp="2026-10-07T08:00:00Z" ripristina la banca allo stato di quel momento, entro una finestra di 30 giorni sui piani a pagamento. Ciò recupera i dati eliminati da migrazioni distruttive e ripristina le modifiche dello schema che non possono essere annullate da una migrazione successiva. L'operazione sostituisce lo stato dell'intero database: non è previsto il ripristino selettivo di tabelle specifiche. Se la migrazione ha danneggiato una tabella ma altre tabelle hanno avuto un'attività normale nell'intervallo, il ripristino ripristinerà anche queste altre tabelle allo stato precedente.

Leggi anche