Idempotency
Falhas de rede acontecem. A maneira segura de fazer retry de uma chamada à API sem risco de duplicação é usar o header Idempotency-Key — o DVS reconhece esse header e faz deduplicação em uma janela de 24 horas.
Como funciona
- Gere um UUID no client por operação lógica (uma classification, uma validation).
- Envie-o no header
Idempotency-Keyem todo retry dessa operação. - Caso seja feito retry e o DVS já tenha processado a request original, o DVS retorna a response original sem reprocessar.
curl -X POST https://dvs-ingestion-api.sandbox.osigu.com/v1/classification-requests \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: f47ac10b-58cc-4372-a567-0e02b2c3d479" \
...
Quando o DVS faz deduplicação
| Cenário | Comportamento do DVS |
|---|---|
Mesmo Idempotency-Key, mesmo body, em até 24h | Retorna a response em cache. Sem novo processamento. Sem nova cobrança. |
Mesmo Idempotency-Key, body diferente, em até 24h | Retorna 409 071-409-idempotency-mismatch. |
Mesmo Idempotency-Key, após 24h | Tratado como nova request. A chave é reutilizada. |
Idempotency-Key diferente, mesmo body | Cria uma nova request. |
Boas práticas
Gere a chave no limite da operação
Gere uma única vez quando for decidido "vou chamar o DVS para classificar este documento". Reutilize-a em qualquer retry dessa mesma chamada. Não regenere a cada retry — isso anula o propósito.
UUID v4 é suficiente
Sem complicar — uuid.uuid4() ou crypto.randomUUID() são suficientes. Evite IDs sequenciais (previsíveis).
Persista a chave junto da operação
Armazene a chave no banco de dados junto da operação que ela representa. Em recuperação após crash, é possível fazer retry com segurança lendo a chave persistida.
Uma chave por operação, não por request
Se a aplicação envia 1000 classifications, gere 1000 chaves. Não compartilhe chaves entre documentos diferentes.
Race conditions
Caso duas requests paralelas cheguem ao DVS com o mesmo Idempotency-Key, apenas uma é processada; a outra aguarda a primeira concluir (até 5 segundos) e retorna a mesma response. Esse comportamento é seguro, mas adiciona latência — procure serializar os retries no client.
Exemplo: loop de retry seguro
import uuid, time, httpx
def classify_with_retry(token, body, max_attempts=3):
idempotency_key = str(uuid.uuid4()) # UMA chave por operação lógica
for attempt in range(max_attempts):
try:
return httpx.post(
"https://dvs-ingestion-api.sandbox.osigu.com/v1/classification-requests",
headers={
"Authorization": f"Bearer {token}",
"Idempotency-Key": idempotency_key, # reutilizada em cada retry
},
json=body,
timeout=30,
).raise_for_status().json()
except httpx.HTTPError:
if attempt == max_attempts - 1:
raise
time.sleep(2 ** attempt)