1. Um timeout deixa uma pergunta em aberto
Um pedido percorre várias fronteiras: cliente, intermediário, aplicação e persistência. Se a resposta se perder depois da criação de um job, o cliente conhece uma falha de comunicação, mas não o resultado do serviço. No laboratório, o servidor cria um pedido de geração de relatório e fecha deliberadamente a ligação antes de responder. O cliente recebe RemoteDisconnected. Essa observação deve manter o estado como desconhecido até existir evidência adicional. Não marques o job como falhado nem como concluído apenas a partir da exceção. Durante suporte L3, regista a referência da operação, a janela temporal e a camada onde a comunicação terminou.
2. A identidade pertence à intenção
Uma tentativa é um envio; uma operação é a intenção que esse envio procura realizar. A chave de idempotência permite ao contrato relacionar várias tentativas com a mesma intenção. No fixture, a identidade inclui tenant, endpoint e chave. Repetir a mesma combinação e o mesmo payload devolve a aceitação guardada sem criar outro job. Alterar o payload com a chave ainda válida recebe 409. Este comportamento é uma escolha explícita do laboratório. A documentação Stripe mostra um contrato real com retenção e comparação de parâmetros, mas não transforma todos os POST de todos os fornecedores em operações idempotentes.
3. Âmbito, acesso e expiração
O serviço deve verificar o acesso atual antes de entregar uma resposta guardada. Um utilizador pode perder autorização depois do primeiro pedido; conhecer a chave não recupera esse acesso. Dois tenants distintos podem usar o mesmo texto de chave sem partilhar resultados quando o namespace inclui o tenant autenticado. O laboratório simula esse contexto com headers X-Lab; estes headers são seletores de teste, não autenticação utilizável. A retenção também limita a garantia. Após dez ticks sintéticos, o fixture esquece a chave, mas conserva o job. Repetir então pode criar outro job. Os dez ticks são uma escolha didática, não uma regra HTTP ou de um fornecedor.
4. Aceitação guardada e estado atual
Uma resposta 202 pode apontar para um recurso onde o consumidor acompanha o trabalho. No exercício, o POST guarda id e state=queued. O runner altera depois o estado do job para succeeded, simulando a conclusão de um worker. Um GET mostra o estado atual, enquanto o replay do POST continua a devolver a aceitação inicial. Não interpretes esse replay como regressão à fila. Acompanha a identidade do job e consulta o recurso apropriado segundo o contrato. No trabalho, distingue o indicador de disponibilidade da API, a taxa de aceitação e a conclusão funcional do processo que o negócio espera.
5. Um orçamento para todas as tentativas
Uma política de recuperação precisa de limites de tentativas, tempo total e autoridade para reenvio. No exemplo guiado, restam 1,5 segundos e a resposta pede uma espera de dois segundos. A política fornecida exige respeitar a espera e proíbe iniciar depois do prazo; portanto, encaminha para a recuperação prevista sem iniciar novo pedido. Considera também as camadas: três tentativas totais do cliente, cada uma com três do gateway, podem produzir nove pedidos ao serviço. Contabiliza o retry onde ele realmente ocorre. Uma melhoria local de resiliência pode aumentar carga e atrasar outros consumidores se não houver coordenação.
6. Exercício de suporte e passagem de turno
Analisa o caso de uma resposta perdida cuja chave já expirou. Prepara uma passagem de turno com a referência de negócio, o resultado conhecido ou desconhecido, a última consulta autorizada, a janela de retenção e o responsável pela decisão de reenvio. Se a consulta confirmar um job concluído, valida o resultado esperado; se mostrar falha, aplica o procedimento aprovado; se permanecer ambígua, mantém a ambiguidade explícita. O laboratório executa HTTP real apenas em loopback e estado em memória. Não ensaia APIs bancárias, efeitos financeiros, TLS, persistência após reinício nem recuperação entre regiões.
# Observações do fixture local, com dados sintéticos
POST /jobs Idempotency-Key: lost -> ligação fechada após criar job 1
POST /jobs Idempotency-Key: lost -> 202 {"id":"1","state":"queued"}
GET /jobs/1 -> 200 {"id":"1","state":"succeeded"}
# O POST repetido conserva a resposta inicial; GET mostra o estado atual.POST cria job 1, a resposta perde-se, e o retry com a mesma identidade devolve job 1. A contagem continua em um; após expiração da chave, outro envio cria job 3 no ensaio.
Armadilhas comuns
Trocar a chave em cada retry; confundir 202 com conclusão; ignorar retenção; tratar headers de teste como autenticação.
Tópicos relacionados: HTTP e HTTPS · Controlo de concorrência · Observabilidade e recuperação
Recupera a intenção original com identidade, consulta e limites explícitos; não deduzas o resultado apenas do transporte.
Referência: Idempotent requests · HTTP semantics RFC9110; OpenAPI3.2.1; selected primary standards and provider contracts consulted2026-09-30