Guía práctica de rollback rápido para deploys Laravel con migrations y feature flags
Por Kevin Marcondes · Publicado el · 8 min de lectura
Esta guía práctica de rollback rápido para deploys Laravel con migrations y feature flags muestra cómo reducir el riesgo y revertir en minutos. Aprenderás a desacoplar cambios de código y base de datos, diseñar migrations reversibles, usar toggles para activar funcionalidades con seguridad y montar un pipeline con releases y symlink atómico.
Qué es “rollback rápido” y cuándo usarlo
Rollback rápido es la capacidad de revertir un deploy en minutos con el mínimo impacto. Combina código, esquema de base de datos y feature flags para mantener el sistema estable.
Equipos pequeños ganan predictibilidad: si algo sale mal, se deshace la versión sin pánico. El secreto es planificar compatibilidad y tener un playbook claro.
- Error crítico tras subir una versión.
- Migration lenta que bloquea peticiones.
- Bug funcional en un flujo específico.
- Incompatibilidad de datos no prevista.
- Inestabilidad en servicios externos tras el cambio.
Estrategia segura: separar código, esquema y datos
Trata el deploy como tres flujos coordinados: código, esquema de base de datos y datos. Reduce el acoplamiento para que revertir código no exija revertir datos.
Aplica el patrón expand/contract: primero expande el esquema de forma compatible, luego cambia el código para usar el nuevo formato y, por último, contrae eliminando lo legado.
Los cambios destructivos requieren más cautela. Evita drops en el deploy inicial. Programa removals cuando las lecturas antiguas ya no existan.
| Cambio | Paso expand | Paso contract | Observaciones |
|---|---|---|---|
| Adicionar coluna | Criar coluna nullable e sem default pesado | Tornar NOT NULL após backfill | Backfill assíncrono ou em janelas de baixa carga |
| Renomear coluna | Criar nova coluna e duplicar escrita | Remover coluna antiga | Mantenha leitura dupla durante migração |
| Alterar tipo | Criar coluna compatível, copiar e trocar uso | Remover coluna antiga | Converta em lotes para evitar locks longos |
| Remover coluna | Introduza feature flag removendo leituras | Dropar depois | Só contraia quando 100% do tráfego não usar |
Migrations tolerantes a rollback en Laravel
Usa migrations revertibles y cambios compatibles. El objetivo es que volver el código no rompa el esquema. Aquí hay un ejemplo de expand/contract.
La documentación oficial de migrations detalla lo básico. Consúltala cuando tengas dudas sobre tipos y compatibilidad.
Para cambios grandes, haz backfill en lotes y fuera de la transacción principal. Evita bloquear tablas por largos periodos.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void
{
// Expand: adicionar coluna compatível
Schema::table('orders', function (Blueprint $table) {
$table->string('checkout_token')->nullable()->after('id');
});
// Backfill assíncrono recomendado (job separado), não aqui.
// Ex.: dispatch(new BackfillCheckoutTokenJob());
}
public function down(): void
{
// Contract reversível: só remova quando o código não depender mais
Schema::table('orders', function (Blueprint $table) {
$table->dropColumn('checkout_token');
});
}
};
Feature flags para desacoplar deploy de release
Las feature flags permiten liberar la funcionalidad tras el deploy, con control fino y reversión instantánea.
Para empezar puedes usar toggles en cache/config o en base de datos. Lo importante es lectura rápida y trazabilidad.
Aprofunda la modelación de flags, scopes y rollout progresivo en la página sobre feature flags en monolitos PHP.
- Guarda flags en cache para lecturas rápidas.
- Estandariza nombres y dominios (ej.: checkout.nuevo_flujo).
- Registra activaciones y desactivaciones.
- Implementa fallback claro cuando la flag esté off.
<?php
namespace App\Support;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
class Feature
{
public static function enabled(string $key): bool
{
$flags = Cache::remember('feature.flags', 30, function () {
return DB::table('feature_flags')->pluck('enabled', 'key')->toArray();
});
return (bool)($flags[$key] ?? false);
}
}
// Uso no código (exemplos):
// if (Feature::enabled('checkout.novo_fluxo')) {
// return app(NewCheckout::class)->handle($request);
// }
// return app(LegacyCheckout::class)->handle($request);
Pipeline de deploy con releases y symlink atómico
Organiza deploys por releases versionadas y un symlink atómico llamado current. Eso permite volver a la release anterior inmediatamente.
Ejecuta migrations compatibles antes del switch de tráfico. Activa feature flags solo tras comprobaciones básicas.
El cómo desplegar una app Laravel en producción cubre optimizaciones como config:cache y optimización de autoload.
- Crear carpeta release con código y dependencias.
- Ejecutar chequear y migrations compatibles.
- Hacer switch atómico del symlink current.
- Calentar cache y realizar healthchecks.
- Activar flags y monitorizar.
set -euo pipefail
RELEASE=$(date +%Y%m%d%H%M%S)
BASE=/var/www/app
NEW=$BASE/releases/$RELEASE
CUR=$BASE/current
# 1) Preparar release
rsync -az --delete ./ $NEW/
cd $NEW
composer install --no-dev --prefer-dist --no-progress
php artisan config:cache && php artisan route:cache
# 2) Pré-mudança de schema compatível
php artisan migrate --force
# 3) Troca atômica
ln -sfn $NEW $CUR
# 4) Pós-deploy
php artisan queue:restart || true
php artisan cache:clear || true
# Rollback manual rápido
# ln -sfn $BASE/releases/<release_anterior> $CUR
Playbook de rollback en minutos
Ten un guion objetivo. El foco inicial es estabilizar el tráfico. Después, analiza la causa y corrige.
Evita depender de migrate:rollback en producción. Deshacer migrations destructivas puede causar pérdida de datos. Prefiere revertir código y flags primero.
- Desactivar flags relacionadas con el error.
- Cambiar symlink a la release estable anterior.
- Reiniciar workers y limpiar caches.
- Congelar nuevas modificaciones hasta el diagnóstico.
- Decidir entre hotfix rápido o post-mortem detallado.
| Incidente | Acción inmediata | Tras estabilizar |
|---|---|---|
| Bug funcional en flujo nuevo | Flag OFF y revisar logs del flujo | Corregir y probar con un subconjunto de usuarios |
| Timeout en migration larga | Interrumpir tráfico al endpoint afectado y vigilar colas | Fatiar backfill y replanear ventana |
| Error 500 tras deploy | Volver symlink y reiniciar workers | Revisar diff de config y dependencias |
| Datos inconsistentes | Detener escrituras problemáticas y aislar casos | Scripts de reconciliación y validación |
Validación post-deploy y automatización en CI/CD
Automatiza chequedas de salud y smoke tests tras el switch. Si fallan, realiza rollback automático a la release anterior.
Incluye pasos de verificación de migrations y latencia básica. Expón un endpoint de healthcheck autenticado.
Pipelines con gates manuales ayudan en cambios sensibles. Combínalos con feature flags para un rollout seguro.
name: deploy
on: [workflow_dispatch]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Run migrations
run: php artisan migrate --force
- name: Switch symlink
run: ./scripts/switch_release.sh
- name: Smoke check
run: curl -fsS https://example.com/health || echo FAIL > .failed
- name: Auto-rollback if failed
if: always()
run: |
if [ -f .failed ]; then
./scripts/rollback_release.sh
exit 1
fi
Referencias útiles y próximos pasos
Profundiza en migrations y deploys en la documentación oficial de Laravel. Revisa tu pipeline con base en el patrón expand/contract.
Consulta contenidos complementarios en estas páginas del sitio. Te ayudarán a reforzar tu proceso.
- Cómo desplegar una app Laravel en producción
- Feature flags en monolitos PHP
- Queues/Queue en Laravel para backfills
Preguntas frecuentes
¿Debo usar php artisan migrate:rollback en producción?
Úsalo con mucha precaución. En general, prioriza revertir el código y desactivar feature flags. Los rollbacks de esquema pueden causar pérdida de datos. Prefiere expand/contract, que permite volver el código sin deshacer cambios compatibles.
¿Cómo lidiar con migrations lentas o que bloquean tablas?
Divídelas en etapas. Primero crea estructuras compatibles y luego haz backfill en lotes fuera de la transacción principal. Usa colas para procesar datos, monitoriza locks y ejecuta en ventanas de menor carga para reducir el impacto.
¿Las feature flags vía .env son suficientes?
Para empezar, pueden servir. Sin embargo, cambiar .env requiere un nuevo deploy. Flags en base de datos con cache permiten activar y desactivar en tiempo real, con auditoría y rollout progresivo, sin reiniciar la aplicación.
¿Cómo tratar filas y Horizon durante un rollback?
Al volver el symlink, reinicia los workers para que carguen el código anterior. Pausar colas críticas durante el cambio evita procesar mensajes con versiones incompatibles, reduciendo inconsistencias en datos.
¿Es posible rollback zero-downtime siempre?
No siempre. El zero-downtime depende de la compatibilidad entre código y esquema, del tamaño de las migrations y del tráfico. Planea expand/contract, usa feature flags y valida en staging para aumentar la probabilidad de rollback sin interrupciones.
¿Quieres reforzar tu plan de rollback?
Si necesitas revisar pipeline, migrations y feature flags para reducir el riesgo de deploys, hablemos de soluciones prácticas para tu contexto.
Hablar sobre rollback seguroVer también
- Guía práctica: configurar failover activo‑pasivo entre dos VPS con Keepalived, HAProxy y lsyncd para uploads sincronizados
- Guía: checklist técnico para preparar un VPS Debian con Docker Compose para aplicaciones PHP en producción
- Guía práctica para dimensionamiento de VPS y tuning de PHP‑FPM para tiendas Magento/OpenMage con picos estacionales: del dimensionamiento a la prueba de carga
- Guía: cómo planificar y ejecutar pruebas de carga en aplicaciones PHP monolito usando k6 y Docker Compose — paso a paso