Guia prático de rollback rápido para deploys Laravel com migrations e feature flags
Por Kevin Marcondes · Publicado em · 7 min de leitura
Este guia prático de rollback rápido para deploys Laravel com migrations e feature flags mostra como reduzir risco e voltar atrás em minutos. Você vai aprender a separar mudanças de código e banco, projetar migrations reversíveis, usar toggles para ativar recursos com segurança e montar um pipeline com releases e symlink atômico.
O que é “rollback rápido” e quando usar
Rollback rápido é a capacidade de reverter um deploy em minutos, com mínimo impacto. Ele combina código, banco e feature flags para manter o sistema estável.
Equipes pequenas ganham previsibilidade: se algo sai do esperado, você desfaz a mudança sem pânico. O segredo é planejar compatibilidade e ter um playbook claro.
- Erro crítico após subir uma versão.
- Migration lenta bloqueando requisições.
- Bug funcional em um fluxo específico.
- Incompatibilidade de dados não prevista.
- Instabilidade em serviços externos após a mudança.
Estratégia segura: separar código, schema e dados
Trate deploy como três fluxos coordenados: código, schema do banco e dados. Reduza acoplamento para que reverter código não exija reverter dados.
Aplique o padrão expand/contract: primeiro expanda o schema de forma compatível, depois mude o código para usar o novo formato, e por fim contraia removendo o legado.
Mudanças destrutivas exigem mais cautela. Evite drops em deploy inicial. Programe remoções quando as leituras antigas já não existirem.
| Mudança | Passo expand | Passo contract | Observações |
|---|---|---|---|
| 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 no Laravel
Use migrations revertíveis e mudanças compatíveis. O objetivo é que voltar o código não quebre o schema. Veja um exemplo de expand/contract.
A documentação oficial de migrations detalha o básico. Consulte quando tiver dúvidas sobre tipos e compatibilidade.
Para alterações grandes, faça backfill em lotes e fora da transação principal. Evite bloquear tabelas por longos períodos.
<?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
Feature flags permitem liberar a funcionalidade depois do deploy, com controle fino e reversão instantânea.
Para começar, você pode usar toggles em config/cache ou banco. O importante é leitura rápida e trilha de auditoria.
Aprofunde a modelagem de flags, escopos e rollout progressivo na página sobre feature flags em monólitos PHP.
- Guarde flags em cache para leituras rápidas.
- Padronize nomes e domínios (ex.: checkout.novo_fluxo).
- Logue ativações e desativações.
- Implemente fallback claro quando a flag estiver 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 com releases e symlink atômico
Organize deploys por releases versionadas e um symlink atômico para current. Isso permite voltar para a release anterior imediatamente.
Execute migrations compatíveis antes do switch de tráfego. Ative feature flags somente após checagens básicas.
Guia de deploy Laravel em produção cobre otimizações como config:cache e otimização de autoload.
- Criar pasta release com código e dependências.
- Executar checagens e migrations compatíveis.
- Fazer switch atômico do symlink current.
- Aquecer cache e healthchecks.
- Ativar flags e monitorar.
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 em minutos
Tenha um roteiro objetivo. O foco inicial é estabilizar o tráfego. Depois, analise causa e corrija.
Evite depender de migrate:rollback em produção. Desfazer migrations destrutivas pode causar perda de dados. Prefira reverter código e flags primeiro.
- Desativar flags relacionadas ao erro.
- Trocar symlink para release estável anterior.
- Reiniciar workers e limpar caches.
- Congelar novas mudanças até diagnóstico.
- Decidir entre hotfix rápido ou post-mortem detalhado.
| Incidente | Ação imediata | Após estabilizar |
|---|---|---|
| Bug funcional em fluxo novo | Flag OFF e logs do fluxo | Corrigir e testar com subset de usuários |
| Timeout em migration longa | Interromper tráfego ao endpoint afetado e observar filas | Fatiar backfill e replanejar janela |
| Erro 500 após deploy | Voltar symlink e reiniciar workers | Rever dif de config e dependências |
| Dados inconsistentes | Desligar gravações problemáticas e isolar casos | Scripts de reconciliação e validação |
Validação pós-deploy e automação no CI/CD
Automatize checagens de saúde e smoke tests após o switch. Em caso de falha, faça rollback automático para a release anterior.
Inclua passos de verificação de migrations e de latência básica. Exponha um endpoint de healthcheck autenticado.
Pipelines com gates manuais ajudam em mudanças sensíveis. Combine com feature flags para um 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
Referências úteis e próximos passos
Aprofunde migrations e deploys na documentação oficial do Laravel. Revise seu pipeline com base no padrão expand/contract.
Veja conteúdos complementares sobre deploy, CI/CD e feature flags nestas páginas do site. Eles ajudam a fortalecer seu processo.
- Migrations do Laravel (documentação).
- Deployments no Laravel (boas práticas).
- Filas/Queue no Laravel para backfills.
Perguntas frequentes
Devo usar php artisan migrate:rollback em produção?
Use com muita cautela. Em geral, priorize reverter o código e desativar feature flags. Rollbacks de schema podem causar perda de dados. Prefira expand/contract, que permite voltar o código sem desfazer mudanças compatíveis.
Como lidar com migrations lentas ou que bloqueiam tabelas?
Divida em etapas. Primeiro crie estruturas compatíveis e depois faça backfill em lotes, fora da transação principal. Use filas para processar dados, monitore locks e rode em janelas de menor carga para reduzir impacto.
Feature flags via .env são suficientes?
Para início, podem ser. Porém, mudar .env exige novo deploy. Flags em banco com cache permitem ativar e desativar em tempo real, com auditoria e rollout progressivo, sem reiniciar a aplicação.
Como tratar filas e Horizon durante rollback?
Ao voltar o symlink, reinicie workers para que carreguem o código antigo. Pausar filas críticas durante a troca evita processar mensagens com versão incompatível, reduzindo inconsistências de dados.
É possível rollback zero-downtime sempre?
Nem sempre. Zero-downtime depende de compatibilidade entre código e schema, tamanho das migrations e tráfego. Planeje expand/contract, use feature flags e valide em staging para aumentar a chance de rollback sem interrupção.
Quer fortalecer seu plano de rollback?
Se você precisa revisar pipeline, migrations e feature flags para reduzir risco de deploy, vamos conversar sobre caminhos práticos para seu contexto.
Falar sobre rollback seguroVeja também
- Guia prático: como configurar failover ativo-passivo entre duas VPS com Keepalived, HAProxy e lsyncd para uploads sincronizados
- Guia: checklist técnico para preparar VPS Debian com Docker Compose para aplicações PHP em produção
- Guia prático para dimensionamento de VPS e tuning de PHP‑FPM para lojas Magento/OpenMage com picos sazonais: do sizing ao teste de carga
- guia prático: reconstruir índices no PostgreSQL em produção usando CREATE INDEX CONCURRENTLY e índices parciais (passo a passo seguro)