ms-ai-architect/skills/ms-ai-engineering/references/api-management/circuit-breaker-ai-resilience.md
Kjell Tore Guttormsen ddce43d8b2 feat(ms-ai-architect): Spor 1 — Port-1-substrat migrert på 4 ikke-advisor-skills (243 Source + 327 Type + 325 TOC + stale-verified poison fjernet) [skip-docs]
Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/
infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk
(fra første ## seksjon), advisor urørt (0 endringer).

To applier-fixes oppdaget under kjøring (TDD, RED→GREEN):
- insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer
  500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor
  scan-vinduet, applierens post-write-assertion fanget + restaurerte).
- normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i
  500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var
  ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent
  utvidelse av carve-out; kun stray metadata-linjer, aldri prosa.

test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet
(fila bærer nå Source). Suite 728/728 grønn.
2026-07-04 10:19:11 +02:00

524 lines
19 KiB
Markdown

# Circuit Breaker Patterns for AI Models
**Last updated:** 2026-02
**Status:** GA
**Category:** API Management & AI Gateway
**Type:** reference
---
## Innhold
- [Introduksjon](#introduksjon)
- [Circuit Breaker State Machine](#circuit-breaker-state-machine)
- [Konfigurasjon](#konfigurasjon)
- [Failure Threshold Tuning](#failure-threshold-tuning)
- [Fallback-policies](#fallback-policies)
- [Recovery-mekanismer](#recovery-mekanismer)
- [Timeout-konfigurasjon](#timeout-konfigurasjon)
- [Avanserte mønstre](#avanserte-mønstre)
- [Anti-mønstre](#anti-mønstre)
- [Komplett resiliens-policy](#komplett-resiliens-policy)
- [For Cosmo](#for-cosmo)
## Introduksjon
Circuit breaker-mønsteret er en grunnleggende resiliensmekanisme for AI-applikasjoner som kommuniserer med Azure OpenAI og andre LLM-backends. Når en backend-tjeneste blir overbelastet eller utilgjengelig, forhindrer circuit breaker at applikasjonen fortsetter å sende forespørsler som uansett vil feile. I stedet "bryter kretsen" og returnerer en feilmelding umiddelbart, slik at backend-tjenesten får tid til å gjenopprette seg.
For Azure AI-tjenester er circuit breaker spesielt viktig fordi Azure OpenAI returnerer 429 (Too Many Requests) med en `Retry-After`-header som kan ha verdier opp til 24 timer. Uten circuit breaker vil applikasjoner fortsette å hamre på en throttlet tjeneste, noe som forverrer situasjonen og kaster bort gateway-ressurser. APIMsintegrerte circuit breaker håndterer dette automatisk ved å respektere `Retry-After`-headeren.
I kombinasjon med backend pools og lastbalansering utgjør circuit breaker selve nervesystemet i en intelligent AI-gateway: den detekterer problemer, isolerer feilende backends, ruter trafikk til friske alternativer, og gjenoppretter normal drift automatisk når backend er tilbake.
---
## Circuit Breaker State Machine
### Tre tilstander
Circuit breaker opererer som en tilstandsmaskin med tre tilstander:
```
Feil > threshold
┌─────────┐ ───────────────► ┌──────────┐
│ CLOSED │ │ OPEN │
│ (normal)│ ◄────────────── │ (trip) │
└─────────┘ Alle OK i └──────────┘
│ half-open │
│ │ Trip duration
│ │ utløpt
│ ┌──────────────┐ │
│ │ HALF-OPEN │◄───┘
│ │ (test) │
│ └──────────────┘
│ │
│ Suksess │ Feil
◄──────────────┘───────────► OPEN
```
| Tilstand | Oppførsel | Varighet |
|----------|-----------|----------|
| **Closed** | Normal drift, alle requests videresendes til backend | Ubegrenset (til feilbetingelse oppstår) |
| **Open** | Alle requests avvises umiddelbart med 503 | Trip duration (konfigurerbar, eller fra Retry-After) |
| **Half-Open** | Et begrenset antall test-requests sendes til backend | Til nok suksesser ELLER ny feil |
### APIM-spesifikk oppførsel
APIMcircuit breaker har noen viktige forskjeller fra den generelle circuit breaker-mønsteret:
| Egenskap | APIM Circuit Breaker |
|----------|---------------------|
| **Konfigurasjons-scope** | Per backend (ikke per API eller policy) |
| **Antall regler** | Kun én regel per backend (p.t.) |
| **Synkronisering** | Ingen mellom gateway-instanser (approksimasjon) |
| **Retry-After respekt** | Ja, dynamisk trip duration basert på backend-respons |
| **Støttede tiers** | Alle unntatt Consumption |
| **Respons ved Open** | 503 Service Unavailable |
---
## Konfigurasjon
### Grunnleggende circuit breaker for Azure OpenAI
```bicep
resource openaiBackend 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-norwayeast'
properties: {
url: 'https://aoai-norwayeast.openai.azure.com/openai'
protocol: 'http'
circuitBreaker: {
rules: [
{
name: 'ai-resilience-rule'
failureCondition: {
count: 3
interval: 'PT1M'
statusCodeRanges: [
{ min: 429, max: 429 }
{ min: 500, max: 599 }
]
}
tripDuration: 'PT10S'
acceptRetryAfter: true
}
]
}
}
}
```
### Attributter forklart
| Attributt | Type | Beskrivelse | Anbefalt verdi for AI |
|-----------|------|-------------|----------------------|
| `failureCondition.count` | int | Antall feil som trigger trip | 3-5 |
| `failureCondition.interval` | duration | Tidsvindu for feil-telling | PT1M (1 minutt) |
| `failureCondition.statusCodeRanges` | array | HTTP-koder som teller som feil | 429 + 500-599 |
| `tripDuration` | duration | Hvor lenge circuit er åpent | PT10S - PT1M |
| `acceptRetryAfter` | bool | Bruk Retry-After header som trip duration | **true** (alltid for AI) |
### Prosentbasert vs. count-basert triggering
APIM støtter to modeller for feil-deteksjon:
**Count-basert (anbefalt for AI):**
```json
{
"failureCondition": {
"count": 3,
"interval": "PT1M",
"statusCodeRanges": [{"min": 429, "max": 429}]
}
}
```
Trigger: 3 eller flere 429-responser innen 1 minutt.
**Prosentbasert:**
```json
{
"failureCondition": {
"percentage": 50,
"interval": "PT1M",
"statusCodeRanges": [{"min": 429, "max": 429}]
}
}
```
Trigger: 50% eller mer av requests feiler innen 1 minutt.
**Anbefaling:** Count-basert er mer forutsigbar for AI-workloads. Prosentbasert kan gi falske positiver ved lav trafikk (2 av 3 requests feiler = 66%).
---
## Failure Threshold Tuning
### Faktorene som påvirker threshold
| Faktor | Lav threshold (1-2) | Høy threshold (5-10) |
|--------|---------------------|---------------------|
| **Reaksjonstid** | Rask, reagerer umiddelbart | Tregere, tolererer noen feil |
| **Falske positiver** | Høy risiko | Lav risiko |
| **Backend-beskyttelse** | Sterk, minimal ekstra belastning | Svakere, flere feil-requests |
| **Anbefalt for** | Kritiske, kapasitetsbegrensede backends | Robuste backends med transiente feil |
### Anbefalte innstillinger per scenario
| Scenario | count | interval | tripDuration | acceptRetryAfter |
|----------|-------|----------|--------------|-----------------|
| **PTU-instans (high priority)** | 3 | PT1M | PT10S | true |
| **PAYGO-instans (fallback)** | 5 | PT2M | PT30S | true |
| **Dev/test** | 2 | PT30S | PT5S | true |
| **Business-critical** | 3 | PT1M | PT10S | true |
| **Batch processing** | 10 | PT5M | PT1M | true |
### Dynamisk trip duration med Retry-After
Når `acceptRetryAfter: true` er satt, overstyrer Azure OpenAIs `Retry-After`-header den konfigurerte `tripDuration`:
```
Scenario: OpenAI returnerer 429 med Retry-After: 30
→ Circuit breaker åpner i 30 sekunder (ikke konfiguert tripDuration)
→ Etter 30 sekunder: half-open → test request
→ Suksess: circuit lukkes
→ Feil: circuit åpner igjen med ny Retry-After
Scenario: OpenAI returnerer 429 med Retry-After: 86400 (1 dag!)
→ Circuit breaker åpner i 24 timer
→ All trafikk rutes til andre backends i poolen
```
> **Viktig advarsel:** Azure OpenAI kan returnere Retry-After verdier opp til 1 dag (86400 sekunder). Med `acceptRetryAfter: true` vil dette bety at backend er utilgjengelig i 24 timer. Sørg for at backend-poolen har nok kapasitet i andre backends til å håndtere dette.
---
## Fallback-policies
### Mønster 1: Backend Pool med automatisk failover
Den enkleste og mest robuste tilnærmingen:
```xml
<policies>
<inbound>
<!-- Backend pool håndterer failover automatisk -->
<set-backend-service backend-id="openai-pool-priority" />
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</inbound>
</policies>
```
Når circuit breaker utløses på Priority 1-backends, ruter APIM automatisk til Priority 2, osv.
### Mønster 2: Retry med backend-bytte
Eksplisitt retry-logikk som bytter backend ved 429:
```xml
<policies>
<backend>
<retry condition="@(context.Response.StatusCode == 429)"
count="3"
interval="0"
first-fast-retry="true">
<set-backend-service backend-id="openai-pool-priority" />
</retry>
</backend>
</policies>
```
**Viktig:** `interval="0"` betyr umiddelbar retry til neste backend, IKKE ventetid. Server-side retries bør aldri ha delay — det holder opp klienten og bruker gateway-ressurser.
### Mønster 3: Graceful Degradation med cache-fallback
```xml
<policies>
<inbound>
<!-- Prøv semantic cache først -->
<azure-openai-semantic-cache-lookup
score-threshold="0.20"
embeddings-backend-id="embeddings-backend"
embeddings-backend-auth="system-assigned" />
<set-backend-service backend-id="openai-pool-priority" />
</inbound>
<on-error>
<choose>
<!-- Alle backends utilgjengelige -->
<when condition="@(context.Response.StatusCode == 503)">
<return-response>
<set-status code="503" reason="AI Service Temporarily Unavailable" />
<set-header name="Retry-After" exists-action="override">
<value>60</value>
</set-header>
<set-body>@{
return new JObject(
new JProperty("error", new JObject(
new JProperty("code", "service_unavailable"),
new JProperty("message", "AI-tjenesten er midlertidig utilgjengelig. Prøv igjen om 60 sekunder."),
new JProperty("type", "circuit_breaker_open")
))
).ToString();
}</set-body>
</return-response>
</when>
</choose>
</on-error>
</policies>
```
### Mønster 4: Fallback til enklere modell
```xml
<policies>
<backend>
<retry condition="@(context.Response.StatusCode == 429 || context.Response.StatusCode == 503)"
count="1"
interval="0"
first-fast-retry="true">
<!-- Fallback til mindre modell -->
<set-backend-service backend-id="openai-gpt4o-mini-backend" />
<rewrite-uri template="/deployments/gpt-4o-mini/chat/completions" />
</retry>
</backend>
</policies>
```
---
## Recovery-mekanismer
### Automatisk recovery
Circuit breaker håndterer recovery automatisk:
```
1. Trip: Circuit åpner (503 til klienter)
2. Wait: tripDuration utløper (eller Retry-After)
3. Half-Open: Test-request sendes til backend
4. Success: Circuit lukkes, normal drift gjenopptas
5. Failure: Circuit åpner igjen, ny tripDuration starter
```
### Recovery-timing
| Kilde | Prioritet | Typisk verdi |
|-------|-----------|--------------|
| `Retry-After` header (når `acceptRetryAfter: true`) | Høyest | 1-86400 sekunder |
| Konfigurert `tripDuration` | Fallback | PT10S - PT1M |
| Default (uten konfigurasjon) | Lavest | PT1M |
### Overvåking av circuit breaker-tilstand
```xml
<outbound>
<!-- Log circuit breaker state -->
<trace source="circuit-breaker" severity="information">
<message>@{
var backendId = context.Backend?.Id ?? "unknown";
var statusCode = context.Response.StatusCode;
return $"Backend: {backendId}, Status: {statusCode}";
}</message>
</trace>
</outbound>
```
**KQL for circuit breaker-hendelser:**
```kusto
ApiManagementGatewayLogs
| where ResponseCode == 503
| extend backendId = tostring(parse_json(BackendResponseBody).backendId)
| summarize CircuitBreakerTrips = count() by backendId, bin(TimeGenerated, 5m)
| render timechart
```
---
## Timeout-konfigurasjon
### Forward-request timeout
Kontroller hvor lenge APIM venter på backend-respons:
```xml
<policies>
<backend>
<forward-request timeout="120" />
</backend>
</policies>
```
**Anbefalte timeouts for AI-workloads:**
| Operasjon | Anbefalt timeout | Begrunnelse |
|-----------|------------------|-------------|
| Chat Completion (standard) | 60-120 sek | GPT-4o kan bruke tid på komplekse prompts |
| Chat Completion (streaming) | 120-180 sek | Streaming starter raskt, men kan vare lenge |
| Embeddings | 30-60 sek | Raskere operasjon, typisk < 10 sek |
| Image Generation (DALL-E) | 120-180 sek | Bildegenerering er CPU-intensivt |
| Assistants API | 180-300 sek | Multi-step agent workflows |
| Batch API | 300-600 sek | Store batch-operasjoner |
### Timeout + Circuit Breaker interaksjon
```
Timeout utløper (120 sek)
→ APIM registrerer det som feil
→ Teller mot circuit breaker threshold
→ Etter N timeouts → Circuit breaker trip
→ Backend fjernes fra pool → Trafikk til alternativer
```
> **Best practice:** Sett timeout lavere enn det du tror er nødvendig. Bedre å få rask feil og retry til annen backend enn å vente 120 sekunder på en hengende request.
---
## Avanserte mønstre
### Mønster: Cascading Circuit Breakers
For multi-tier arkitekturer der APIM ruter til mellomtjenester som igjen kaller Azure OpenAI:
```
Client → APIM [CB-1] → Custom Service [CB-2] → Azure OpenAI
```
```bicep
// CB-1: APIM → Custom Service
resource customServiceBackend 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
properties: {
circuitBreaker: {
rules: [{
failureCondition: {
count: 5
interval: 'PT2M'
statusCodeRanges: [
{ min: 502, max: 504 }
]
}
tripDuration: 'PT30S'
}]
}
}
}
```
Applikasjons-nivå CB-2 implementeres med Polly (.NET), resilience4j (Java), eller tilsvarende.
### Mønster: Health Endpoint Monitoring
Kombiner circuit breaker med aktiv health checking:
```xml
<policies>
<inbound>
<!-- Sjekk health endpoint før ruting -->
<send-request mode="new"
response-variable-name="healthCheck"
timeout="5"
ignore-error="true">
<set-url>@("https://aoai-norwayeast.openai.azure.com/openai/models?api-version=2024-10-21")</set-url>
<set-method>GET</set-method>
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</send-request>
<choose>
<when condition="@(((IResponse)context.Variables["healthCheck"]).StatusCode != 200)">
<!-- Backend er nede, bruk fallback direkte -->
<set-backend-service backend-id="openai-fallback-pool" />
</when>
<otherwise>
<set-backend-service backend-id="openai-primary-pool" />
</otherwise>
</choose>
</inbound>
</policies>
```
> **Merk:** Health endpoint monitoring legger til latens og backend-belastning. Bruk det kun for scenarier der circuit breaker alene ikke gir rask nok failover.
---
## Anti-mønstre
| Anti-mønster | Problem | Løsning |
|--------------|---------|---------|
| **Ingen circuit breaker** | Backend overbelastes, cascading failure | Aktiver circuit breaker på alle AI-backends |
| **For lav threshold (count=1)** | Falske positiver ved transiente feil | Bruk count=3-5 for produksjon |
| **For lang tripDuration** | Backend er unødvendig utilgjengelig | Bruk `acceptRetryAfter: true` |
| **Ignorere Retry-After** | Hammer backend som eksplisitt ber om pause | Sett `acceptRetryAfter: true` alltid |
| **Server-side delay** | Retry med sleep/delay holder opp klienter | Bruk `interval="0"` med backend pool failover |
| **Timeout for lang** | Gateway-ressurser brukt opp på hengende requests | Sett realistiske timeouts per operasjonstype |
| **Mangle monitoring** | Ingen innsikt i circuit breaker-oppførsel | Emit metrikk + KQL dashboards |
---
## Komplett resiliens-policy
```xml
<policies>
<inbound>
<!-- 1. Token rate limiting -->
<llm-token-limit
counter-key="@(context.Subscription.Id)"
tokens-per-minute="50000"
estimate-prompt-tokens="true" />
<!-- 2. Backend pool med circuit breaker -->
<set-backend-service backend-id="openai-pool-priority" />
<!-- 3. Managed Identity auth -->
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</inbound>
<backend>
<!-- 4. Retry til annen backend ved 429 -->
<retry condition="@(context.Response.StatusCode == 429)"
count="3"
interval="0"
first-fast-retry="true">
<set-backend-service backend-id="openai-pool-priority" />
</retry>
<!-- 5. Timeout -->
<forward-request timeout="120" />
</backend>
<outbound>
<!-- 6. Token metrikk -->
<llm-emit-token-metric namespace="ai-gateway">
<dimension name="Backend" value="@(context.Backend?.Id ?? "unknown")" />
<dimension name="StatusCode" value="@(context.Response.StatusCode.ToString())" />
</llm-emit-token-metric>
</outbound>
<on-error>
<!-- 7. Graceful degradation -->
<choose>
<when condition="@(context.Response.StatusCode == 503)">
<return-response>
<set-status code="503" reason="AI Service Unavailable" />
<set-header name="Retry-After" exists-action="override">
<value>60</value>
</set-header>
<set-body>{"error":{"code":"all_backends_unavailable","message":"Alle AI-backends er midlertidig utilgjengelige"}}</set-body>
</return-response>
</when>
</choose>
</on-error>
</policies>
```
---
## For Cosmo
- Circuit breaker er obligatorisk for alle Azure OpenAI backends i produksjon -- uten det risikerer du cascading failures og bortkastet gateway-kapasitet mot throttlede backends.
- Sett ALLTID `acceptRetryAfter: true` for Azure OpenAI backends. Azure OpenAI returnerer presise Retry-After verdier som gir optimal recovery-timing. Uten dette bruker du den statiske tripDuration som kan være for kort eller for lang.
- Anbefalt baseline: `count: 3`, `interval: PT1M`, `tripDuration: PT10S`, `acceptRetryAfter: true`. Juster count opp for PAYGO-backends med mer toleranse.
- Kombiner circuit breaker med backend pools for automatisk failover: når PTU-backend tripper, ruter APIM automatisk til PAYGO-backends uten klient-endringer.
- Advarsler: Azure OpenAI kan returnere Retry-After opp til 86400 sekunder (1 dag). Sørg for at arkitekturen har nok alternative backends til å håndtere langvarige circuit breaks.