Esta es la restricción que hace distinta a una migración de cualquier otro cambio: durante al menos unos segundos, el esquema que estás cambiando lo sigue leyendo la versión que todavía atiende peticiones.
Eso descarta toda una categoría de migraciones «obviamente inofensivas». Renombrar una columna no es inofensivo, porque la versión vieja no conoce el nombre nuevo. Eliminar una columna no es inofensivo, porque la versión vieja puede seguir escribiendo en ella.
Lo que sí es inofensivo es añadir:
Schema::table('consumers', function (Blueprint $table) {
$table->string('webhook_url')->nullable();
$table->text('webhook_secret')->nullable();
});
Cada columna nueva admite null y es un añadido. La versión vieja, todavía en marcha mientras esto se ejecuta, no tiene idea de que webhook_url existe ni necesita tenerla. Sigue leyendo y escribiendo las columnas que conoce. La versión nueva encuentra las columnas ya ahí cuando cambia el tráfico. Nadie tiene que coordinar el milisegundo exacto en que el esquema y el código cambian juntos, porque el cambio de esquema por sí solo no rompe nada.
Un cambio que no es un añadido, un renombrado por ejemplo, se convierte en tres despliegues: añadir la columna nueva y escribir en las dos, hacer el backfill con un comando reiniciable del Capítulo 17 y pasar las lecturas a la nueva, y después eliminar la columna vieja cuando nada la toque. Es más lento. También es la única versión en la que ninguna petición falla nunca.
--force se salta la pregunta de «¿estás seguro?», porque un pipeline no puede contestar a una pregunta.
--isolated toma un bloqueo antes de migrar. Si despliegas en dos servidores a la vez, los dos intentarán ejecutar la misma migración, y sin el bloqueo el segundo falla con una tabla que ya existe. Con él, uno ejecuta las migraciones y el otro espera y no encuentra nada que hacer. (Documentación de Laravel: Database: Migrations › Running Migrations.)
Una migración que falla en producción debería detener el despliegue, haciendo ruido. Nunca la envuelvas en algo que se trague el código de salida. Código roto atendiendo tráfico sobre un esquema que nunca recibió es peor que un despliegue que no ocurrió.
Volver atrás de forma segura
Revertir el código y revertir un esquema son dos operaciones distintas, y tratarlas como una sola es la manera en que un incidente de cinco minutos se convierte en uno de cinco horas.
Revertir el código, si despliegas por versiones, es casi instantáneo. La versión anterior sigue en disco con sus dependencias instaladas. Revertir significa apuntar otra vez el enlace simbólico hacia ella: el mismo cambio atómico que te trajo hasta aquí, ejecutado al revés.
Revertir un esquema no es instantáneo ni es seguro por defecto. Un método down() se escribe para deshacer limpiamente una migración, no para deshacerla mientras código en marcha puede depender de lo que elimina.
# Mal: revertir el esquema en el mismo movimiento
php artisan migrate:rollback --step=1
# ... y luego volver a la versión anterior
Los dos comandos son reales y los dos funcionan. El problema es la suposición que hay detrás. Si algo escribió en las columnas nuevas entre el despliegue y la vuelta atrás, migrate:rollback elimina esas columnas y esos datos desaparecen. No se revierten. Desaparecen. Has cambiado un bug por una pérdida de datos.
# Bien: revertir el código y dejar el esquema
# volver a la versión anterior
# las columnas nuevas se quedan; la vieja no las leía
Como la migración era un añadido, a la versión vieja le da igual que webhook_url exista. Nunca la buscó. Revertir el código basta para detener la hemorragia. Si el esquema de verdad tiene que cambiar, eso es una migración nueva hacia delante, escrita con calma, y no un método down() ejecutado bajo la presión de un incidente contra una base de datos de cuyo estado nadie está seguro.
Cuando alguien de tu equipo esté atendiendo una alerta a las dos de la mañana, no recordará cuáles de tus migraciones es seguro revertir y cuáles borran algo. No le hagas adivinar. Con migraciones solo hacia delante y que solo añaden, la respuesta es siempre la misma: revierte primero el código, y normalmente ya está.