# Runbook: Circuit Breaker Open

## Signal

**Alerte déclenchée**:
- `VezaCircuitBreakerOpen` - Circuit breaker en état OPEN depuis > 5 minutes

**Symptômes observables**:
- Métrique: `veza_circuit_breaker_state == 2` (2 = OPEN)
- Logs: `circuit breaker opened for [service_name]`
- Erreurs: Toutes les requêtes vers le service externe sont rejetées immédiatement
- Endpoints affectés: OAuth, Stream service, autres dépendances externes

## Hypothèses

1. **Service externe down** - OAuth provider, Stream server, etc. ne répond plus
2. **Service externe lent** - Timeouts répétés, service surchargé
3. **Réseau** - Problème de connectivité vers service externe
4. **Configuration circuit breaker** - Seuils trop stricts (peu probable)

## Vérifications

### 1. Identifier le circuit breaker affecté

```bash
# Vérifier métriques Prometheus
curl -s "http://localhost:9090/api/v1/query?query=veza_circuit_breaker_state" | jq

# Exemple de réponse:
# {
#   "metric": {
#     "circuit_breaker_name": "oauth_service"
#   },
#   "value": [1234567890, "2"]
# }
# 2 = OPEN, 1 = HALF_OPEN, 0 = CLOSED
```

### 2. Vérifier logs application

```bash
# Chercher ouverture circuit breaker
grep -i "circuit breaker opened\|circuit breaker open" /var/log/veza-backend-api/*.log | tail -20

# Chercher erreurs service externe
grep -i "oauth\|stream.*error\|timeout" /var/log/veza-backend-api/*.log | tail -50
```

### 3. Tester service externe directement

```bash
# Pour OAuth service (exemple)
curl -v https://oauth-provider.example.com/health

# Pour Stream service (exemple)
curl -v http://stream-server:8082/health

# Vérifier timeout
timeout 5 curl http://<service-external>/health
```

### 4. Vérifier métriques circuit breaker

```bash
# Échecs consécutifs
curl -s "http://localhost:9090/api/v1/query?query=veza_circuit_breaker_consecutive_failures" | jq

# Total échecs
curl -s "http://localhost:9090/api/v1/query?query=veza_circuit_breaker_failures_total" | jq

# Requêtes rejetées
curl -s "http://localhost:9090/api/v1/query?query=veza_circuit_breaker_requests_total{result=\"rejected\"}" | jq
```

## Actions Correctives

### Si service externe down

1. **Vérifier santé service externe**:
   - Consulter dashboard/monitoring du service externe
   - Vérifier logs du service externe
   - Contacter équipe responsable du service

2. **En attendant réparation**:
   - **Option A**: Service peut fonctionner en mode dégradé (fonctionnalités optionnelles désactivées)
   - **Option B**: Si critique, mettre service en maintenance

3. **Documenter impact**:
   - Quelles fonctionnalités sont affectées?
   - Combien d'utilisateurs impactés?

### Si service externe lent

1. **Vérifier charge service externe**:
   ```bash
   # Si accès monitoring
   curl http://<service-external>/metrics | grep cpu\|memory\|requests
   ```

2. **Augmenter timeout temporairement** (si configurable):
   - Modifier timeout dans `internal/services/circuit_breaker.go`
   - **⚠️ Attention**: Augmenter timeout peut masquer le problème

3. **Contacter équipe service externe**:
   - Signaler latence élevée
   - Demander investigation

### Si réseau

1. **Tester connectivité**:
   ```bash
   telnet <service-host> <service-port>
   # ou
   nc -zv <service-host> <service-port>
   ```

2. **Vérifier firewall/routing**:
   ```bash
   traceroute <service-host>
   ```

3. **Vérifier DNS**:
   ```bash
   nslookup <service-host>
   dig <service-host>
   ```

### Forcer réouverture circuit breaker (si nécessaire)

**⚠️ DANGER**: Ne forcer la réouverture que si le service externe est confirmé opérationnel.

Le circuit breaker se rouvrira automatiquement après le timeout configuré (généralement 60s). Pour forcer manuellement:

1. **Redémarrer application** (force reset circuit breaker):
   ```bash
   sudo systemctl restart veza-backend-api
   # ou
   docker restart veza-backend-api
   ```

2. **Attendre timeout automatique**:
   - Circuit breaker passe en HALF_OPEN après timeout
   - Si prochaine requête réussit → CLOSED
   - Si prochaine requête échoue → re-OPEN

## Post-Mortem Notes

### À documenter après résolution

- **Circuit breaker affecté**: `oauth_service` / `stream_service` / autre
- **Cause racine**: Service externe down / Lent / Réseau / Autre
- **Durée de l'incident**: De [heure début] à [heure fin]
- **Impact**: Fonctionnalités affectées, utilisateurs impactés
- **Actions prises**: Liste des actions correctives
- **Actions préventives**:
  - [ ] Améliorer monitoring service externe
  - [ ] Ajouter alertes côté service externe
  - [ ] Revoir configuration circuit breaker (seuils, timeout)
  - [ ] Implémenter fallback/retry logic

### Métriques à surveiller post-incident

- `veza_circuit_breaker_state` - Doit revenir à 0 (CLOSED)
- `veza_circuit_breaker_consecutive_failures` - Doit revenir à 0
- `veza_circuit_breaker_requests_total{result="success"}` - Doit augmenter
- `veza_circuit_breaker_requests_total{result="rejected"}` - Doit s'arrêter d'augmenter

## Configuration Circuit Breaker

**Fichier**: `internal/services/circuit_breaker.go`

**Paramètres par défaut** (sony/gobreaker):
- **MaxRequests**: 3 (half-open state)
- **Interval**: 60s (timeout avant réouverture)
- **Timeout**: 60s (durée état OPEN)
- **ReadyToTrip**: 5 échecs consécutifs → OPEN

**Modification** (si nécessaire):
```go
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{
    MaxRequests: 3,
    Interval:    60 * time.Second,
    Timeout:     60 * time.Second,
    ReadyToTrip: func(counts gobreaker.Counts) bool {
        return counts.ConsecutiveFailures > 5
    },
})
```

## Références

- Métriques circuit breaker: `internal/metrics/circuit_breaker.go`
- Service circuit breaker: `internal/services/circuit_breaker.go`
- Documentation gobreaker: https://github.com/sony/gobreaker
