Módulo 6: Proyecto — Pipeline CI/CD Completo con Claude Code

Failure Paths y Observabilidad

Failure Paths y Observabilidad

Descripción

Las cápsulas 03-04 cubrieron el happy path: lo que pasa cuando todo sale bien. Pero un pipeline production-ready maneja también los casos donde algo falla. Esta cápsula cubre los failure paths del pipeline y la observabilidad necesaria para detectarlos, diagnosticarlos, y responder.

Vas a implementar Phase 4 (post-deploy monitoring + auto-rollback + diagnóstico) y diseñar el comportamiento del pipeline para los 5 modos principales de fallo: code review/security/tests bloquean, staging deploy falla, métricas degradan en producción, approval rechazado, y deploy a producción falla. Cada uno con respuesta clara y observable.

Al terminar, vas a tener un pipeline que falla con gracia en cada modo de fallo, monitoring activo post-deploy, y observabilidad que el equipo usa para tomar decisiones con datos.


Los 5 Failure Modes

1. PR REVIEW BLOQUEA (Phase 1)
   - Code review encontró critical issues → bloquea merge
   - Security scan encontró critical → bloquea merge
   - Tests fallan → bloquea merge
   
   Comportamiento: el PR no puede mergear hasta resolver
   Visibilidad: status checks rojos en el PR + comments

2. PRE-DEPLOY VALIDATION FALLA (Phase 2)
   - Readiness validation detecta env vars faltantes
   - Migrations problemáticas
   
   Comportamiento: deploy a staging no procede
   Visibilidad: workflow run failed + readiness report como artifact

3. STAGING DEPLOY FALLA (Phase 3)
   - Deploy script error
   - Smoke tests staging fallan
   - Métricas de staging degradan
   
   Comportamiento: production gate no se activa
   Visibilidad: workflow falla, equipo notificado vía Slack

4. APPROVAL RECHAZADO (Phase 3)
   - Reviewer humano click "Reject"
   - Timeout (24 hrs sin approval)
   
   Comportamiento: deploy a producción no procede
   Visibilidad: PR comment + workflow status

5. PRODUCTION FALLA POST-DEPLOY (Phase 4)
   - Smoke tests producción fallan
   - Métricas degradan después del deploy
   
   Comportamiento: rollback automático + diagnóstico + notification
   Visibilidad: PagerDuty incident + Slack + Issue de postmortem

Para cada uno: comportamiento esperado + visibilidad + recovery path.


Phase 4: Implementación Completa

# Continuación del workflow staged-deployment.yml

  monitor-post-deploy:
    needs: deploy-production
    runs-on: ubuntu-latest
    outputs:
      rollback_needed: ${{ steps.monitor.outputs.rollback_needed }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: '3.11', cache: 'pip' }
      
      - run: pip install anthropic requests
      
      - name: Monitor production for 10 minutes
        id: monitor
        env:
          METRICS_API_URL: ${{ secrets.METRICS_API_URL }}
          METRICS_API_TOKEN: ${{ secrets.METRICS_API_TOKEN }}
        run: |
          python scripts/monitor_post_deploy.py
          if [ $? -eq 1 ]; then
            echo "rollback_needed=true" >> $GITHUB_OUTPUT
          else
            echo "rollback_needed=false" >> $GITHUB_OUTPUT
          fi
        continue-on-error: true  # ← rollback es separado

  rollback:
    needs: [deploy-production, monitor-post-deploy]
    if: needs.monitor-post-deploy.outputs.rollback_needed == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Execute rollback
        env:
          PREVIOUS_RELEASE: ${{ needs.deploy-production.outputs.previous_release }}
        run: |
          echo "🚨 Rolling back production to $PREVIOUS_RELEASE"
          ./scripts/rollback.sh production "$PREVIOUS_RELEASE"
      
      - name: Verify rollback with smoke tests
        run: ./scripts/smoke_tests.sh https://app.example.com

  diagnose:
    needs: [deploy-production, monitor-post-deploy, rollback]
    if: always() && needs.monitor-post-deploy.outputs.rollback_needed == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      
      - uses: actions/setup-python@v5
        with: { python-version: '3.11', cache: 'pip' }
      
      - run: pip install anthropic requests
      
      - name: Generate diagnosis
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_REPOSITORY: ${{ github.repository }}
          DEPLOY_SHA: ${{ needs.deploy-production.outputs.new_release }}
          PREVIOUS_SHA: ${{ needs.deploy-production.outputs.previous_release }}
        run: python scripts/diagnose_incident.py
      
      - name: Create postmortem issue
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_REPOSITORY: ${{ github.repository }}
        run: python scripts/create_postmortem_issue.py
      
      - name: Notify team of rollback
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
          PAGERDUTY_TOKEN: ${{ secrets.PAGERDUTY_TOKEN }}
        run: python scripts/notify_rollback.py

  notify-success:
    needs: [deploy-production, monitor-post-deploy]
    if: needs.monitor-post-deploy.outputs.rollback_needed == 'false'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-python@v5
        with: { python-version: '3.11' }
      
      - run: pip install requests
      
      - name: Notify success
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
        run: python scripts/notify_success.py

Lo importante:

  • monitor-post-deploy con continue-on-error: true — fallar acá no rompe el workflow, solo dispara rollback
  • rollback solo corre si rollback_needed == 'true'
  • diagnose corre incluso si rollback falla (if: always()) — el diagnóstico es info crítica
  • notify-success y diagnose son mutuamente exclusivos

Comportamiento por Failure Mode

Failure Mode 1: PR Review bloquea

LO QUE PASA:
1. Developer abre PR
2. Phase 1 corre los 3 jobs en paralelo
3. Security scan detecta SQL injection (critical)
4. Job security-scan retorna exit 1
5. Status check "security-scan" se marca rojo en el PR
6. Branch protection bloquea el merge
7. Comment en el PR explica el finding

LO QUE EL DEVELOPER VE:
- Status checks: ❌ security-scan failed
- Comment del bot con el finding específico
- Botón "Merge" deshabilitado
- Instrucciones para resolver

LO QUE EL EQUIPO VE:
- Nada hasta que el developer lo resuelva
- Si lo necesita escalar, abre conversación en el PR

RECOVERY PATH:
1. Developer resuelve el finding (o usa override label si es falso positivo)
2. Push de fix
3. Workflow re-corre
4. Status verde → merge habilitado

Failure Mode 2: Pre-Deploy Validation Falla

LO QUE PASA:
1. PR mergea a main
2. Phase 2 corre: readiness-validation
3. Detecta que `STRIPE_API_KEY` no está configurada en environment "production"
4. Job retorna exit 1
5. Phase 3 no comienza (deploy-staging tiene needs: readiness-validation)

LO QUE EL EQUIPO VE:
- Workflow run failed
- Artifact `readiness-report.json` con el detalle
- Notification en Slack si configurada

RECOVERY PATH:
1. Configurar la env var faltante en GitHub Settings → Environments
2. Re-disparar el workflow manualmente:
   - Actions → workflow run → "Re-run all jobs"
3. O hacer un push trivial (`git commit --allow-empty -m "trigger ci"`)

Failure Mode 3: Staging Deploy Falla

LO QUE PASA:
1. Deploy a staging script falla (ej. imagen Docker no encuentra)
2. Job deploy-staging retorna exit 1
3. validate-staging no corre (needs: deploy-staging)
4. Production gate nunca se activa

LO QUE EL EQUIPO VE:
- Workflow failed en staging
- Logs del deploy script
- Notification automática (si configurada)
- Producción NO afectada (no llegó a deployarse)

RECOVERY PATH:
1. Investigar logs del deploy script
2. Si es issue de infraestructura: arreglar y re-disparar
3. Si es issue del código: revertir el commit en main
4. Re-mergear cuando esté listo

Failure Mode 4: Approval Rechazado

LO QUE PASA:
1. Pipeline llegó a "Waiting for approval to deploy: production"
2. Reviewer click "Reject" (o timeout 24hr sin approval)
3. Job deploy-production cancelado
4. Phase 4 no corre

LO QUE EL EQUIPO VE:
- Workflow run en estado "cancelled"
- Comment del reviewer (si dejó razón)
- Producción NO afectada

RECOVERY PATH:
1. Si fue rechazo intencional: revisar la razón, ajustar el código si necesario
2. Si fue timeout sin attention: comunicar al equipo, potencialmente delegar approval
3. Re-disparar el workflow después de fixes

Failure Mode 5: Production Falla Post-Deploy

LO QUE PASA:
1. Deploy a producción exitoso
2. Phase 4 corre monitor-post-deploy
3. Métricas degradan en los primeros 5 min:
   - error_rate sube a 8% (threshold: 2%)
   - latency_p95 sube 3x baseline
4. monitor-post-deploy retorna exit 1
5. rollback se dispara automáticamente
6. Rollback completo en ~3 min
7. diagnose corre y genera postmortem
8. notify_rollback envía a Slack/PagerDuty

LO QUE EL EQUIPO VE:
- Slack: "🚨 Auto-rollback executed in production"
  + diagnóstico breve
  + link al postmortem issue
- PagerDuty: incident creado (si configurado)
- GitHub Issue creado con postmortem draft
- Producción estabilizada en versión anterior

RECOVERY PATH:
1. On-call abre el postmortem issue
2. Valida el diagnóstico automático
3. Identifica root cause exacto
4. Decide: re-aplicar fix vs investigar más
5. Cuando esté listo: nuevo PR con el fix correcto
6. Pipeline normal a producción

Observabilidad: Lo Que el Equipo Necesita Ver

DASHBOARDS NECESARIOS:

1. Pipeline Health Dashboard
   - Tasa de éxito de deploys (%)
   - Duración promedio del pipeline
   - Failures por phase
   - MTTR (mean time to recovery) cuando hay rollback

2. Cost Dashboard
   - Costo por run (API + runners)
   - Costo mensual acumulado
   - Top jobs por costo
   - Comparación vs budget

3. Quality Dashboard
   - PRs con security findings (criticos/high)
   - Test coverage trend
   - Code review findings categorizados
   - False positive rate del bot

4. Production Health (post-deploy)
   - Error rate trend (con markers de deploys)
   - Latency p95 trend
   - Throughput
   - Rollbacks ejecutados (count + razones)

Implementar dashboards en tu sistema de observability:

# scripts/export_pipeline_metrics.py
"""Exportar métricas del pipeline a tu sistema de monitoring."""
import os
import json
from datetime import datetime
import requests


def export_to_datadog(metrics: dict):
    """Push métricas a Datadog."""
    api_key = os.environ.get("DATADOG_API_KEY")
    if not api_key:
        return
    
    series = []
    for name, value in metrics.items():
        series.append({
            "metric": f"ci.pipeline.{name}",
            "points": [[int(datetime.utcnow().timestamp()), value]],
            "tags": [f"workflow:{os.environ['GITHUB_WORKFLOW']}",
                     f"branch:{os.environ['GITHUB_REF_NAME']}"],
        })
    
    requests.post(
        "https://api.datadoghq.com/api/v1/series",
        headers={"DD-API-KEY": api_key, "Content-Type": "application/json"},
        json={"series": series},
    )


def main():
    # Métricas a exportar al final del workflow
    metrics = {
        "duration_seconds": int(os.environ.get("WORKFLOW_DURATION", 0)),
        "phase1_pass": 1 if os.environ.get("PHASE1_STATUS") == "success" else 0,
        "phase2_pass": 1 if os.environ.get("PHASE2_STATUS") == "success" else 0,
        "phase3_pass": 1 if os.environ.get("PHASE3_STATUS") == "success" else 0,
        "rollback_executed": 1 if os.environ.get("ROLLBACK_EXECUTED") == "true" else 0,
    }
    
    export_to_datadog(metrics)
    print(f"Pipeline metrics exported: {metrics}")


if __name__ == "__main__":
    main()

Agregar al final del workflow:

  export-metrics:
    needs: [deploy-production, monitor-post-deploy, rollback, diagnose]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-python@v5
        with: { python-version: '3.11' }
      
      - run: pip install requests
      
      - name: Export pipeline metrics
        env:
          DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
          ROLLBACK_EXECUTED: ${{ needs.monitor-post-deploy.outputs.rollback_needed }}
        run: python scripts/export_pipeline_metrics.py

Alerting: Lo Que Despierta a la Gente

ALERTING TIERS:

TIER 1 — DESPERTAR ON-CALL (PagerDuty/SMS):
  ✅ Auto-rollback ejecutado
  ✅ Producción failure smoke tests
  ✅ Pipeline failure en último step antes de prod
  
TIER 2 — NOTIFICATION ALTA PRIORIDAD (Slack channel #alerts):
  ⚠️  Critical security finding bloqueó merge
  ⚠️  Multiple deploys fallaron (último día)
  ⚠️  Costos del pipeline excedieron budget mensual

TIER 3 — INFO (Slack channel #ci):
  💬 Deploy exitoso a producción
  💬 Pipeline summary diario
  💬 New high-severity findings (no critical)

NUNCA ALERTAR:
  ❌ Deploy individual exitoso (no es alerta, es info)
  ❌ PR mergeado (es la info típica de GitHub)
  ❌ Comments del bot (esperados)

PagerDuty Integration

# scripts/notify_rollback.py — extender con PagerDuty
import requests

def trigger_pagerduty_incident(
    summary: str,
    severity: str,
    details: dict,
    routing_key: str,
):
    """Crear incident en PagerDuty."""
    payload = {
        "routing_key": routing_key,
        "event_action": "trigger",
        "payload": {
            "summary": summary,
            "source": "ci-pipeline",
            "severity": severity,
            "custom_details": details,
        },
    }
    
    r = requests.post(
        "https://events.pagerduty.com/v2/enqueue",
        json=payload,
        timeout=10,
    )
    return r.ok

Trampas Comunes en Failure Paths

1. Rollback que también falla

Síntoma: Métricas degradan, rollback se ejecuta, pero el rollback en sí falla. Producción queda mal.

Por qué pasa: El script de rollback no tiene validación post-execution.

Cómo corregir: Después del rollback, smoke tests obligatorios. Si fallan, escalar a humano (PagerDuty crítico).

2. Diagnóstico ignorado

Síntoma: Diagnose genera postmortem issue, pero nadie lo lee. Próximo incident similar pasa de nuevo.

Por qué pasa: El issue queda sin asignar.

Cómo corregir: Auto-asignar a un on-call específico. Slack notification que linkea al issue. SLA: review en 24hr.

3. Notification spam

Síntoma: Slack lleno de notifs. El equipo deja de leer. Cuando hay un alert real, se pierde.

Por qué pasa: Tier 1/2/3 mezclados en el mismo canal.

Cómo corregir: Separar canales. #alerts solo para tier 1. #ci-info para info general. PagerDuty solo para tier 1.

4. Métricas exportadas pero sin dashboards

Síntoma: Estás exportando a Datadog/Prometheus, pero nadie miró un dashboard nunca.

Por qué pasa: Construyeron exports antes de construir consumers.

Cómo corregir: Construir el dashboard primero (aunque sea vacío). Después agregar exports. Sin consumer, no hay valor en exportar.

5. No probar failure paths antes de necesitarlos

Síntoma: Primer rollback real revela bugs en el script de rollback. Bajo presión, rollback fail.

Por qué pasa: Testing solo del happy path.

Cómo corregir: Game days regulares — simular failures intencionalmente para validar que el pipeline responde correctamente. Chaos engineering aplicado al CI/CD.


Diagnóstico

Pregunta 1: ¿Tu pipeline cubre los 5 failure modes con comportamiento explícito?

Si solo tienes happy path, vas a improvisar bajo presión. Cobertura explícita = respuesta predecible.

Pregunta 2: ¿Tu rollback automático tiene smoke tests post-rollback?

Sin esto, puedes tener "rollback exitoso" según el script pero producción mal.

Pregunta 3: ¿Tienes tiers de alerting separados (PagerDuty / Slack alerts / Slack info)?

Sin tiers, el equipo se desensibiliza y los alerts importantes se pierden.

Pregunta 4: ¿Construiste dashboards de pipeline antes que exports?

Si tienes exports sin dashboards, gastas tiempo sin valor. Dashboard primero, después optimizar exports.

Pregunta 5: ¿Probaste tus failure paths intencionalmente?

Si nunca lo hiciste, el primer real falla mal. Game days = practicar bajo control.


Ejercicios

Ejercicio 1: Implementar Phase 4 (Difícil)

Implementa los 4 jobs adicionales: monitor-post-deploy, rollback, diagnose, notify-success/rollback. Verifica que:

  1. monitor corre 10 min después del deploy
  2. rollback se dispara si métricas degradan
  3. diagnose genera postmortem issue
  4. notifications llegan a Slack

Ejercicio 2: Game day simulado (Medio)

Simula un failure mode end-to-end:

  1. Configura un endpoint mock que retorna 500 al X% de requests
  2. Configura thresholds bajos en monitoring
  3. Mergeas un PR que activa el endpoint
  4. Verifica que el pipeline ejecuta rollback + diagnose correctamente
  5. Lee el postmortem auto-generado

Ejercicio 3: Dashboard de pipeline (Difícil)

Crea un dashboard en tu sistema de observability con:

  1. Pipeline duration trend
  2. Success rate por phase
  3. Costo por run (calculado de tokens + minutes)
  4. Rollbacks ejecutados (count + razones)

Resumen

  • 5 failure modes principales: PR review, pre-deploy validation, staging deploy, approval rechazado, production post-deploy
  • Cada modo con comportamiento explícito: qué pasa, qué ve el equipo, recovery path
  • Phase 4 integra monitor + rollback + diagnose + notify
  • 3 tiers de alerting: PagerDuty (crítico), Slack alerts (alto), Slack info (rutina)
  • Dashboards primero, exports después — sin consumers no hay valor
  • Game days — probar failure paths intencionalmente antes de necesitarlos
  • if: always() en jobs críticos como diagnose — corren incluso si jobs anteriores fallan

Próxima cápsula: 06 — Documentación, optimización y retrospectiva. Última cápsula del módulo. Conviertes el pipeline funcional en pipeline transferible: documentación operacional, optimizaciones de costos, retrospectiva con métricas. Lo que separa "funciona en mi máquina" de "production-ready".


Recursos Adicionales

  1. Site Reliability Engineering: Postmortem Culture — Capítulo de Google
  2. PagerDuty Events API — Para integration
  3. Datadog API — Métricas custom
  4. Prometheus + Grafana — Stack open-source
  5. Chaos Engineering Principles — Para game days
  6. The Site Reliability Workbook: Incident Response — Capítulo aplicable