APIM Circuit Breaker com Azure OpenAI
Visão Geral
Ao consumir modelos do Azure OpenAI em produção, depender de um único endpoint representa um risco real. Basta uma instância ficar indisponível ou atingir limites de throttling para que toda a aplicação seja impactada.
Neste artigo, construímos uma arquitetura resiliente utilizando o Azure API Management (APIM) como camada de proteção entre o cliente e os serviços de IA.
O ponto de partida são dois backends do Azure OpenAI (oiaws01 e oiaws02), ambos configurados com Managed Identity. A partir deles, criamos um Load Balancer Pool no APIM, distribuindo o tráfego em um modelo 50/50 entre os dois endpoints.
Em seguida, habilitamos o Circuit Breaker, que detecta falhas consecutivas e "abre o circuito", impedindo que novas requisições sejam enviadas a um backend com problemas. Nesse estado, o APIM passa a responder com 503 – Service Unavailable, incluindo o header Retry-After, até que o backend se recupere.
O ponto mais crítico está na configuração das políticas XML. Posicionar o set-backend-service dentro do bloco <retry> garante que cada tentativa seja roteada novamente pelo Load Balancer, evitando que as retentativas atinjam sempre o mesmo backend com falha.
Todo o fluxo foi validado usando o Trace do APIM, onde é possível acompanhar, passo a passo:
- Seleção do backend no pool
- Autenticação via Managed Identity
- Fallback para o segundo endpoint
- Resposta final ao cliente
Por fim, exploramos a camada de observabilidade. Os eventos de abertura do Circuit Breaker são capturados e enviados para uma Storage Queue, de onde um Logic App os exporta via HTTP POST para o Elastic Observability, permitindo monitoramento em tempo real de quando e por que os circuitos são abertos.
Diagrama
Diagrama do fluxo da Requisição http, Load balancer falhas e Circuit Break
1. Criando os Backends para Azure OpenAI
O primeiro passo é registrar no APIM os endpoints que representam as instâncias do Azure OpenAI. Neste cenário, criamos dois backends apontando para:
- https://oiaws01.openai.azure.com/openai
- https://oiaws02.openai.azure.com/openai
Cada backend funciona como uma abstração dentro do APIM — ele encapsula a URL, as credenciais e as configurações de resiliência (como o Circuit Breaker) em um único recurso reutilizável.
Dois backends registrados no APIM: openapi01-openai-endpoint e openapi02-openai-endpoint, apontando para os respectivos endpoints do Azure OpenAI.
Configuração de Managed Identity
Para que o APIM consiga se autenticar nos backends sem expor chaves de API, configuramos Managed Identity. O Azure API Management pode apresentar credenciais ao backend utilizando cabeçalhos de autorização, parâmetros de consulta ou certificados de cliente — mas a abordagem mais segura e moderna é usar a identidade gerenciada.
Com essa configuração, o APIM solicita um token OAuth ao Azure AD usando sua própria identidade (System Assigned), e o apresenta ao backend como um Bearer token. Não há segredos para rotacionar, não há chaves para vazar.
Backend openia02-openai-endpoint configurado com Managed Identity (System Assigned) apontando para https://cognitiveservices.azure.com/.
Em alguns cenários — especialmente quando a configuração via portal não é suficiente ou quando precisamos de controle granular — é necessário configurar a autenticação diretamente nas políticas XML do APIM:
<authentication-managed-identity resource="https://cognitiveservices.azure.com" output-token-variable-name="msi-access-token" />
<!-- Add Authorization header with token -->
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + (string)context.Variables["msi-access-token"])</value>
</set-header>
Essa abordagem é útil quando você precisa reutilizar o token em múltiplas policies ou quando o backend exige um formato específico de apresentação das credenciais.
Teste Básico
Com os backends e a autenticação configurados, o próximo passo é validar que tudo funciona. Um teste simples direto no console do APIM confirma a conectividade:
Parâmetros:
deployment-id: o1
api-version: 2025-01-01-preview
Request body:
{
"messages": [
{
"role": "user",
"content": "I am going to Paris, what should I see?"
}
],
"max_completion_tokens": 40000,
"model": "o1"
}Teste no console do APIM confirmando resposta 200 OK do Azure OpenAI (modelo o1) via Managed Identity.
2. Criando o Load Balancer (LB)
Ter dois backends funcionando individualmente é um bom começo, mas não garante resiliência por si só. Se a API estiver apontada para um backend fixo e ele cair, o serviço para. É aqui que entra o Load Balancer Pool.
O Load Balancer Pool é um recurso do APIM que agrupa múltiplos backends e distribui o tráfego entre eles segundo regras configuráveis. Em vez de apontar a política set-backend-service para um backend individual, apontamos para o pool — e o APIM se encarrega de escolher para qual instância enviar cada requisição.
Criação do Load Balancer Pool
Criamos um pool chamado LB01 contendo os dois backends OpenAI. A distribuição foi configurada como 50/50 com pesos customizados, o que significa que cada backend recebe metade do tráfego em condições normais.
Benefícios imediatos:
- Distribuição de carga — nenhum backend recebe 100% das requisições
- Alta disponibilidade — se um backend falhar, o outro absorve o tráfego (quando combinado com retry)
- Flexibilidade — pesos e prioridades podem ser ajustados sem alterar código
Com o pool criado, qualquer política que referencia backend-id="LB01" passa automaticamente a ter balanceamento de carga. Mas distribuir tráfego não é suficiente — precisamos também detectar e isolar falhas. É o que o Circuit Breaker faz.
3. Entendendo e Configurando o Circuit Breaker
O que é o Circuit Breaker?
O Circuit Breaker é um padrão de resiliência para sistemas distribuídos, inspirado nos disjuntores elétricos. Assim como um disjuntor corta a energia quando detecta uma sobrecarga para proteger o circuito, o Circuit Breaker em software interrompe temporariamente as chamadas a um serviço que está falhando, evitando que falhas em cascata derrubem toda a aplicação.
Sem Circuit Breaker, quando um backend começa a falhar, o sistema continua enviando requisições para ele — consumindo recursos, aumentando latência e potencialmente causando timeout em cadeia. Com o Circuit Breaker, o sistema "aprende" que aquele backend está com problemas e para de enviar tráfego até que ele se recupere.
Os Três Estados do Circuit Breaker
O Circuit Breaker opera em três estados bem definidos:
| Estado | Comportamento | Analogia |
|---|---|---|
| Closed (Fechado) | Tráfego flui normalmente para o backend. Falhas são contadas silenciosamente. | Disjuntor ligado — energia passa. |
| Open (Aberto) | Todas as requisições são imediatamente rejeitadas com 503 Service Unavailable + header Retry-After. Nenhuma chamada chega ao backend. | Disjuntor desligado — energia cortada para proteger o circuito. |
| Half-Open (Meio-aberto) | Após o trip duration expirar, o circuito permite uma requisição de teste. Se ela for bem-sucedida, volta para Closed. Se falhar, volta para Open. |
A transição entre os estados segue este fluxo:
Por que isso importa para Azure OpenAI?
No contexto de IA generativa, uma chamada ao Azure OpenAI pode levar vários segundos. Se o backend está retornando erros (429 throttling, 500 internal error, 404 modelo não encontrado), cada tentativa desperdiça tempo precioso. O Circuit Breaker garante fail-fast: em vez de esperar 30 segundos por um timeout, o cliente recebe imediatamente um 503 com a informação de quando pode tentar novamente.
Configuração no APIM
Configuração do Circuit Breaker: 1 falha dispara abertura, status codes 400–599, trip duration de 1 minuto e Retry-After habilitado.Os parâmetros configurados foram:
| Parâmetro | Valor | Significado |
|---|---|---|
| Rule name | rulecb | Identificador da regra |
| Failure count | 1 | Basta 1 falha para abrir o circuito (agressivo, ideal para testes) |
| Failure interval | 1 hora | Janela de tempo para contagem de falhas |
| Failure status code range | 400-599 | Qualquer resposta 4xx ou 5xx conta como falha |
| Failure error reason | BackendConnectionFailure | Tipo de erro que dispara o Circuit Breaker |
| Trip duration | 1 minuto | Tempo que o circuito permanece aberto antes de tentar Half-Open |
| Check Retry-After header | True (Accept) | Respeita o header Retry-After do backend |
Nota sobre o Failure Count: Em produção, um valor de 1 é muito agressivo — uma única falha transitória abriria o circuito. Valores entre 3 e 5 são mais comuns. Para este artigo, usamos 1 para facilitar a demonstração.
Comportamento Observado
- Após falhas consecutivas, o APIM retorna 503 – Service Unavailable
- O Circuit Breaker aparece como aberto no portal do Azure
- O header Retry-After é incluído na resposta
4. Configurando as Políticas para usar o LB
Com backends, Load Balancer e Circuit Breaker configurados, o último passo é garantir que as políticas XML do APIM conectem tudo corretamente. Aqui estão os pontos que fazem toda a diferença entre uma configuração que funciona e uma que parece funcionar.
Ponto Importante #1 — Apontar para o Pool, não para o Backend
A política set-backend-service deve referenciar o Load Balancer Pool, e não um backend individual:
<set-backend-service id="apim-generated-policy" backend-id="LB01" />
Se você apontar diretamente para openapi01-openai-endpoint, perde todo o benefício do balanceamento e do failover automático.
Ponto Importante #2 — Buffer do Request Body
A política de retry deve usar forward-request com buffer-request-body="true". Sem isso, o body da requisição é consumido na primeira tentativa e não está disponível para retentativas:
<backend>
<retry condition="@(context.Response.StatusCode == 404)" count="2" interval="1" first-fast-retry="true">
<forward-request buffer-request-body="true" />
</retry>
</backend>
Ponto Importante #3 — Retry balanceado pelo LB
Este é o ponto mais crítico e o que diferencia uma configuração robusta de uma ingênua. Se o set-backend-service estiver fora do bloco <retry>, o backend é selecionado uma única vez — e todas as retentativas vão para o mesmo endpoint. Se esse endpoint está falhando, todas as retentativas falham também.
A solução é colocar o set-backend-service dentro do <retry>:
<backend>
<retry condition="@(context.Response.StatusCode == 404)" count="2" interval="1" first-fast-retry="true">
<set-backend-service id="apim-generated-policy" backend-id="LB01" />
<forward-request buffer-request-body="true" />
</retry>
</backend>
Com essa configuração, a cada tentativa o Load Balancer é consultado novamente e pode rotear para um backend diferente. O resultado prático: se oiaws02 falha, a retentativa vai para oiaws01 automaticamente.
Explicação dos Elementos
| Elemento | Descrição |
|---|---|
| <retry> | Define lógica de repetição (retry) para chamadas a serviços de backend |
| condition="@(context.Response.StatusCode == 404)" | Condição para acionar a repetição: resposta HTTP 404 (Not Found) |
| count="2" | Número máximo de tentativas adicionais (além da original) |
| interval="1" | Intervalo de 1 segundo entre as tentativas |
| first-fast-retry="true" | A primeira repetição é imediata, sem aguardar o intervalo |
| <forward-request /> | Envia a requisição ao serviço de backend |
5. Trace — Validação do Fluxo
onfiguração feita, é hora de validar. O Trace do APIM permite acompanhar passo a passo o que acontece com cada requisição — desde a entrada até a resposta final ao cliente. É a ferramenta definitiva para confirmar que o Load Balancer, o Circuit Breaker e o retry estão funcionando em conjunto.
No cenário de teste, o backend oiaws02 não possui o modelo o1 deployado, então retorna 404. O Trace mostra exatamente como o APIM lida com isso:
- Backend selecionado no pool:
Backend '(, https://oiaws02.openai.azure.com/openai)' was selected in Backend pool 'LB01'.
- Autenticação via Managed Identity:
Managed identity token is added to Authorization header.
- Primeira tentativa — falha (oiaws02 não possui o modelo o1):
Request sent to https://oiaws02.openai.azure.com/openai/deployments/o1/chat/completions → Response: 404 Not Found
- Retry com novo backend selecionado pelo LB:
Backend service URL was changed. oldBackendServiceUrl: https://oiaws02.openai.azure.com/openai newBackendServiceUrl: https://oiaws01.openai.azure.com/openai
- Segunda tentativa — sucesso:
Request sent to https://oiaws01.openai.azure.com/openai/deployments/o1/chat/completions → Response: 200 OK
- Resposta final ao cliente:
Response has been sent to the caller in full
O cliente recebeu a resposta com sucesso, sem saber que houve uma falha nos bastidores. Isso é resiliência transparente.
6. Events — Monitoramento do Circuit Breaker
Ter resiliência é essencial, mas saber quando ela está sendo acionada é igualmente importante. Se o Circuit Breaker está abrindo com frequência, pode indicar um problema que precisa de atenção — um backend degradado, um modelo removido, ou limites de throttling sendo atingidos repetidamente.
Captura de Eventos via Storage Queue
O APIM foi configurado para capturar eventos de abertura do Circuit Breaker e enviá-los para uma Storage Queue. Cada vez que um circuito abre, um evento é publicado com todos os detalhes relevantes.
Observação: Após essa configuração, a abertura do Circuit Breaker pode não aparecer mais no Trace, embora continue sendo registrada na fila.
Criação da Event Subscription no Event Grid com os tipos "Circuit Breaker Opened" e "Circuit Breaker Closed" selecionados para capturar eventos de abertura e fechamento do circuito.
Painel de Events do APIM mostrando 20 eventos publicados e entregues com sucesso à Storage Queue via subscription cbapim (Circuit Breaker Opened/Closed).Exemplo de Evento
{
"id": "e5da5756-61b9-42cf-8097-f8a684f1b74c",
"topic": "/subscriptions/.../resourceGroups/apimappgw/providers/Microsoft.ApiManagement/service/apimappgwws01",
"subject": "/backends/openapi01-openai-endpoint/circuit-breaker/rules/cb01",
"data": {
"backendName": "openapi01-openai-endpoint",
"circuitBreaker": {
"rules": {
"cb01": {
"tripDuration": "00:00:15"
}
}
}
},
"eventType": "Microsoft.ApiManagement.CircuitBreaker.Opened",
"dataVersion": "1.0",
"metadataVersion": "1",
"eventTime": "2025-08-14T15:41:30.948673Z"
}
O evento nos diz exatamente: qual backend foi isolado (openapi01-openai-endpoint), qual regra foi violada (cb01), e por quanto tempo o circuito ficará aberto (15 segundos).
7. Export Events com Logic Apps → Elastic Observability
A Storage Queue resolve o problema de captura, mas para monitoramento em tempo real e dashboards operacionais, precisamos levar esses dados para uma plataforma de observabilidade. Neste caso, utilizamos o Elastic Observability.
Fluxo de Integração
O pipeline completo funciona assim:
- Circuit Breaker abre → evento é publicado na Storage Queue
- Logic App é acionado pelo trigger da fila
- Logic App recupera a API Key no Key Vault (via Managed Identity — sem segredos hardcoded)
- Logic App envia os dados via HTTP POST para o Elastic Observability
Exemplo de Chamada HTTP
POST https://apim-a5eaba.es.eastus.azure.elastic.cloud/apim/_doc
Content-Type: application/json
Authorization: ApiKey ...
Body: JSON do evento do Circuit Breaker.
Configuração no Elastic
Para receber e visualizar os eventos, é necessário:
- Criar um índice (apim) para armazenar os documentos
- Criar uma API Key com permissão de escrita no índice
- Obter a URL do projeto Elastic Cloud
- Criar uma View/Dashboard para visualizar os eventos de abertura do Circuit Breaker
Com esse pipeline completo, a equipe de operações consegue responder rapidamente a perguntas como: "Quantas vezes o circuito abriu nas últimas 24 horas?", "Qual backend está mais instável?", "Os problemas coincidem com horários de pico?".
Conclusão
A combinação de Load Balancer + Circuit Breaker + Retry inteligente no APIM transforma uma arquitetura frágil em uma arquitetura resiliente — onde falhas em backends individuais são tratadas de forma transparente, sem impacto para o cliente.
Os pontos-chave para levar:
- Nunca exponha um único endpoint de Azure OpenAI diretamente — use o APIM como abstração
- Managed Identity elimina o gerenciamento manual de segredos entre APIM e backends
- O set-backend-service deve estar dentro do <retry> para que retentativas sejam distribuídas pelo Load Balancer
- Circuit Breaker protege contra falhas em cascata — fail-fast é melhor que timeout lento
- Observabilidade não é opcional — se o circuito está abrindo, você precisa saber
Referências
- Azure API Management backends | Microsoft Learn
- Azure API Management Backends | Microsoft Learn
- Circuit Breaker Pattern - Azure Architecture Center | Microsoft Learn