Guía práctica de rollback rápido para deploys Laravel con migrations y feature flags

Por · Publicado el · 8 min de lectura

Guía práctica de rollback rápido para deploys Laravel con migrations y feature flags
Foto: Marek Prášil / Pexels

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);

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.

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 seguro

Ver también