Initial addition of ms-ai-architect plugin to the open-source marketplace. Private content excluded: orchestrator/ (Linear tooling), docs/utredning/ (client investigation), generated test reports and PDF export script. skill-gen tooling moved from orchestrator/ to scripts/skill-gen/. Security scan: WARNING (risk 20/100) — no secrets, no injection found. False positive fixed: added gitleaks:allow to Python variable reference in output-validation-grounding-verification.md line 109. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
18 KiB
Circuit Breaker Patterns for AI Models
Last updated: 2026-02 Status: GA Category: API Management & AI Gateway
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
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):
{
"failureCondition": {
"count": 3,
"interval": "PT1M",
"statusCodeRanges": [{"min": 429, "max": 429}]
}
}
Trigger: 3 eller flere 429-responser innen 1 minutt.
Prosentbasert:
{
"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: truevil 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:
<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:
<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
<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
<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
<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:
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:
<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
// 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:
<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
<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: truefor 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.