← REST APIs: integrar aplicações e diagnosticar falhas
08 / 12 · 60 MIN

Alterações concorrentes e recuperação verificável

Usa pré-condições e patches atómicos, interpreta conflitos e define a evidência necessária para produção.

1. A versão lida faz parte da decisão

Dois operadores podem editar o mesmo recurso a partir de uma leitura idêntica. Se cada um enviar uma representação completa sem proteção, o último pode apagar silenciosamente a alteração do primeiro. Um ETag forte representa a versão observada; If-Match condiciona a operação a essa versão. No ensaio, ambos leem "v1". O primeiro altera owner e recebe "v2". O segundo continua a enviar "v1" e recebe 412, sem alterar o recurso. O conflito torna visível que a intenção foi preparada sobre uma base desatualizada. Não é um pedido de remover a proteção para terminar mais depressa.

2. Três condições com significados diferentes

O laboratório exige If-Match e responde 428 quando ele falta. Com uma versão antiga, responde 412. Um tag fraco W/"v2" também não satisfaz a comparação forte de If-Match com "v2". O asterisco tem outro significado: exige que exista uma representação atual, mas não compara com a versão anteriormente lida. No fixture, If-Match: * permite a alteração do recurso existente. Não o uses como substituto da versão específica quando precisas de impedir uma atualização perdida. Estes códigos e condições devem constar do runbook com a ação correspondente, respeitando o contrato real de cada serviço.

3. Reconciliar conteúdo antes de reenviar

Num exemplo de encaminhamento, a equipa A muda destination e a equipa B pretende mudar owner. O documento antigo da equipa B ainda contém o destino anterior. Trocar apenas o ETag para o novo valor faria passar a pré-condição, mas continuaria a repor dados antigos. Lê o estado atual, compara as intenções e constrói a alteração autorizada que preserva o trabalho concorrente. Se houver incompatibilidade, obtém uma decisão do responsável. Mesmo após reconciliar, envia a nova pré-condição para detetar outra corrida. Uma janela apertada exige uma decisão de prioridade, não uma suposição de que as alterações são compatíveis.

4. Um patch não pode ficar aplicado a meio

JSON Patch permite uma sequência de operações, incluindo test e replace. O teste verifica o valor e o tipo; não converte texto "12" para número 12 nem escreve o valor esperado. Quando usado com PATCH HTTP, a alteração deve ser atómica. O ensaio prepara uma cópia do documento, substitui owner e depois testa um estado incorreto. O teste falha; a cópia é descartada e o documento original permanece completo. O código didático suporta apenas test e replace em dois campos textuais. Não é uma biblioteca JSON Patch completa nem prova de todas as regras de JSON Pointer, arrays ou números. Para um nome literal batch/day na raiz, o path JSON Pointer é /batch~1day: ~1 representa a barra e ~0 representa o til. /batch/day percorre dois níveis distintos. Este caso de sintaxe é estudado separadamente; não é executado pelo fixture limitado.

5. Erros acionáveis sem divulgar internals

Uma resposta de conflito deve ajudar o consumidor a escolher uma ação. Problem Details permite um identificador de tipo e informação sobre a ocorrência. No fixture, key-payload-conflict distingue reutilização incompatível de patch-test-failed. Não programes a lógica apenas comparando frases traduzidas em detail; usa o contrato do tipo e o código HTTP. Uma referência de ocorrência pode ligar suporte a diagnóstico com acesso restrito. Não devolvas tokens, stack traces ou dados de outros tenants como ajuda de debugging. Também não assumes que o URL type contém instruções que o cliente deve abrir ou executar automaticamente.

6. Da evidência local à aceitação operacional

Os onze grupos observados incluem uma criação perante dois POST concorrentes e rejeição de uma escrita desatualizada. Isso demonstra o comportamento do fixture executado com um lock de processo. Uma implementação distribuída precisa de identidade exclusiva entre workers, persistência e recuperação consistente entre o efeito e o seu resultado guardado. Testa quedas antes e depois de cada fronteira, reinícios, perda de resposta e expiração; compara operações únicas com tentativas. Se houver efeitos externos, uma transação local não os torna automaticamente atómicos. Resume a aceitação com evidência funcional, riscos por resolver e dono da recuperação, sem prometer exactly-once de ponta a ponta.

PATCH /document
Content-Type: application/json-patch+json
If-Match: "v2"

[{"op":"replace","path":"/owner","value":"team-c"},
 {"op":"test","path":"/state","value":"approved"}]

# Fixture: state=draft -> 409; owner anterior preservado; revisão continua v2.
NA PRÁTICA

Leituras A e B: ETag "v1". PATCH A: 200, owner=team-a, ETag "v2". PATCH B com "v1": 412. O owner permanece team-a.

Armadilhas comuns

Atualizar só o ETag; remover If-Match; confundir asterisco com igualdade; aplicar parcialmente um patch; generalizar um lock local.

Tópicos relacionados: HTTP e HTTPS · Controlo de concorrência · Observabilidade e recuperação

Leva esta ideia contigo

Conflitos precisam de reconciliação e evidência; o mecanismo de recuperação deve cobrir as mesmas fronteiras que os efeitos.

Criar conta

Referência: RFC9110 HTTP Semantics · HTTP semantics RFC9110; OpenAPI3.2.1; selected primary standards and provider contracts consulted2026-09-30