Una strategia di deploy con rollback in PHP non consiste nel conservare un pulsante per tornare alla versione precedente. È una progettazione operativa che consente di ritirare codice senza lasciare dati incompatibili, job asincroni duplicati o processi in corso che eseguono regole già scartate. Il rollback deve essere un'opzione predisposta prima della pubblicazione, non una reazione improvvisata durante un incidente.
I deploy piccoli riducono il raggio d'impatto: introducono meno variabili, facilitano l'identificazione della modifica che ha causato il problema e abbreviano il recupero. Tuttavia, una modifica limitata può influire su pagamenti, autenticazione, autorizzazioni, inventario o comunicazioni. Per questo, la dimensione della modifica non sostituisce i controlli tecnici né criteri espliciti per interrompere una pubblicazione.
Il rollback si progetta prima che si verifichi un incidente

Ripristinare il codice è semplice solo quando la modifica non ha alterato lo stato condiviso. In produzione, una versione potrebbe aver scritto dati, inviato messaggi a una coda, attivato un'attività pianificata o chiamato un servizio esterno. Tornare a un commit precedente senza esaminare questi effetti può nascondere l'errore iniziale e crearne uno più difficile da diagnosticare.
Prima di approvare un deploy, il team deve poter rispondere a quattro domande:
- Quale artefatto sarà pubblicato: artefatto identificabile, creato una sola volta e disponibile per il ripristino.
- Quale stato cambia: schema del database, cache, file, indici di ricerca, code, provider esterni e configurazione.
- Quale versione può leggere e scrivere tale stato: codice nuovo, codice precedente o entrambi durante una finestra temporale.
- Quale segnale impone di agire: soglia di errori, fallimento di un percorso critico, ritardo nella coda, degrado della latenza o impatto funzionale confermato.
L'unità di rollback deve essere definita. Può essere l'intera applicazione, un servizio, un consumer di coda o una funzionalità attivata tramite configurazione. Non è opportuno confondere il deploy, che installa software, con la release, che rende disponibile un comportamento. Separarli consente di distribuire codice inattivo ed esporlo in seguito, dopo aver validato le condizioni tecniche.
Classificare le modifiche in base alla loro capacità di rollback
Non tutte le modifiche ammettono lo stesso trattamento. Un adeguamento di presentazione o una correzione interna senza cambiamenti di stato è generalmente reversibile ripristinando l'artefatto precedente. Al contrario, una migrazione distruttiva, una modifica del contratto API o una nuova regola di business che ha già prodotto effetti esterni richiede una strategia aggiuntiva.
Modifiche normalmente reversibili
- Correzioni della logica che mantengono i contratti di input e output.
- Modifiche ai template, purché non dipendano da campi eliminati.
- Nuovi percorsi o endpoint che non modificano risorse esistenti.
- Ottimizzazioni interne senza modifiche dello schema né della semantica.
Modifiche che richiedono compatibilità temporanea
- Ridenominazione o sostituzione di colonne, campi JSON ed eventi.
- Modifiche di formato nei messaggi di coda o nei webhook.
- Nuovi vincoli di validazione su dati già esistenti.
- Modifiche ad autenticazione, autorizzazioni o regole di calcolo.
- Integrazioni che creano addebiti, ordini, notifiche o modifiche in sistemi esterni.
Per i dati condivisi, il pattern più sicuro è in genere espandere, migrare, contrarre. Prima si aggiunge una struttura compatibile, poi il codice supporta temporaneamente il formato vecchio e quello nuovo, si migrano o popolano i dati necessari e, solo dopo aver ritirato definitivamente la versione precedente, si elimina ciò che è obsoleto. Ad esempio, aggiungere una colonna nullable e scrivere entrambi i campi durante una transizione è recuperabile; rinominare o eliminare direttamente una colonna usata dalla versione precedente non lo è.
Le migrazioni devono essere trattate come deliverable indipendenti dal codice. Una migrazione solo forward può essere corretta, ma il piano deve allora dichiarare che il rollback dell'applicazione non implica il rollback dello schema. Evitare una migrazione automatica di downgrade se può eliminare dati generati dopo la modifica o se il suo risultato dipende dallo stato reale della produzione.
Preparare artefatti, configurazione e precondizioni
Lo stesso artefatto deve avanzare tra gli ambienti. Risolvere le dipendenze o modificare il codice direttamente su ciascun server impedisce di sapere quale versione sia in esecuzione e rende difficile ripristinarne una nota. In un'applicazione PHP, l'artefatto può includere il codice versionato e le dipendenze risolte; la configurazione sensibile e specifica dell'ambiente deve essere iniettata tramite meccanismi esterni, non incorporata nel pacchetto.
Registrare almeno l'identificatore di versione, la data di pubblicazione, la configurazione funzionale rilevante e il responsabile della decisione. Questo accelera sia l'indagine sia il ritorno a una versione specifica.
Prima del deploy, verificare in modo automatizzato e visibile:
- Test unitari, di integrazione e di contratto proporzionati alla modifica.
- Risoluzione delle dipendenze e compatibilità con la versione di PHP, le estensioni e i servizi richiesti.
- Stato delle migrazioni, piano di espansione dei dati e tempo di esecuzione stimato.
- Stato di salute delle dipendenze: database, cache, storage, API interne e provider critici.
- Capacità e comportamento di worker, code e attività pianificate.
- Disponibilità dell'artefatto precedente e procedura testata per ripristinarlo.
I controlli non devono limitarsi al fatto che il processo PHP risponda. Un health check può confermare che PHP-FPM è attivo e, tuttavia, non rilevare un errore di autorizzazione, una query lenta o un consumer bloccato. Definire piccoli percorsi sintetici che rappresentino operazioni critiche senza eseguire azioni irreversibili.
Pubblicare gradualmente con responsabili e limiti chiari
L'esposizione graduale riduce la portata di un guasto, ma funziona solo se il traffico o le istanze possono essere separati realmente. Si può aggiornare una frazione delle istanze, attivare una funzionalità per un segmento controllato o instradare una parte delle richieste verso la nuova versione. La scelta dipende dall'architettura e dal tipo di stato condiviso.
Assegnare ruoli espliciti durante la finestra di pubblicazione:
- Una persona esegue e registra i passaggi.
- Un'altra osserva metriche, log e trace rilevanti.
- Un responsabile ha l'autorità di interrompere o effettuare il rollback senza attendere approvazioni ambigue.
- Il team business o di supporto conosce gli effetti attesi se la modifica interessa un'operazione sensibile.
Stabilire anche una finestra di osservazione. Non basta pubblicare, vedere una risposta HTTP corretta e passare alla modifica successiva. Alcuni difetti emergono quando viene elaborata una coda, scade una cache, viene eseguita un'attività pianificata o un utente completa un flusso più lungo.
Verificare dopo: servizio, dati ed effetti di business
La verifica successiva deve combinare segnali tecnici e funzionali. Le metriche generali sono utili, ma una latenza media stabile può nascondere il fallimento di un'operazione minoritaria e critica.
- Percorsi critici: autenticazione, lettura e scrittura principali, pagamenti, creazione di ordini o azioni con autorizzazioni.
- Errori: eccezioni PHP, risposte 5xx, aumenti inattesi di 4xx, errori di validazione e guasti delle dipendenze.
- Prestazioni: latenza per endpoint, saturazione dei worker, connessioni al database e consumo di risorse.
- Elaborazione asincrona: dimensione e anzianità della coda, retry, messaggi falliti e idempotenza.
- Effetti di business: transazioni incomplete, duplicati, cambiamenti di stato non validi o cali nelle conversioni che il team può verificare.
I criteri decisionali devono essere verificabili. Proseguire se i percorsi definiti funzionano, non vi è un aumento sostenuto degli errori e le code rimangono entro il ritardo accettabile. Interrompere l'espansione se compare un'anomalia che richiede ancora una diagnosi. Effettuare il rollback se l'artefatto precedente è compatibile con lo stato attuale e il ripristino riduce chiaramente l'impatto. Correggere in avanti se il rollback romperebbe la compatibilità, non annullerebbe gli effetti esterni o richiederebbe più tempo di una correzione isolata e validata.
Gestire code e processi avviati da una versione ritirata
I worker sono una fonte comune di rollback incompleti. È possibile ritirare il codice web mentre restano messaggi creati dalla nuova versione o processi di lunga durata che continuano a eseguire la logica precedente. Il piano deve indicare come svuotare, mettere in pausa, riavviare o isolare i consumer senza perdere tracciabilità.
Si consideri un flusso ipotetico: un'applicazione PHP pubblica un messaggio per confermare un ordine. La nuova versione aggiunge un campo al messaggio e modifica lo stato dell'ordine prima di inviarlo. Se deve essere ritirata, il consumer precedente deve ignorare in sicurezza il campo aggiuntivo oppure il messaggio deve avere una versione che ne consenta l'instradamento a un consumer compatibile. Inoltre, la conferma deve usare una chiave idempotente affinché un retry non produca due azioni esterne.
{
"event": "order.confirmation_requested",
"schema_version": 2,
"idempotency_key": "operacion-unica",
"order_id": "identificador"
}
Prima di effettuare il rollback, mettere in pausa l'ingresso di nuovi job se necessario, identificare i messaggi in transito e confermare quali consumer possano elaborarli. Successivamente, esaminare i fallimenti e i retry in modo controllato. Non eliminare una coda per recuperare velocità: potrebbe rimuovere prove necessarie o lasciare operazioni di business parzialmente completate.
Trasformare il piano in una pratica ripetibile

Una strategia matura non dipende dalla memoria individuale. Mantenere un runbook breve per servizio con i comandi approvati, la posizione dei log, i dashboard di osservazione, i responsabili, le condizioni di arresto e i limiti noti del rollback. Provare la procedura in un ambiente rappresentativo, soprattutto dopo modifiche a infrastruttura, code, migrazioni o integrazioni.
Dopo ogni incidente o rollback, esaminare se ha fallito il rilevamento, la compatibilità, l'automazione o la decisione. L'obiettivo non è evitare ogni rollback; è poter scegliere tra rollback e correzione in avanti con informazioni sufficienti, senza trasformare un incidente localizzato in una perdita di dati o in un'interruzione più grave.



