Garantias
O que se sustenta, e o que não.
Esta página declara as garantias sobre as quais você pode construir e nomeia os estados surpreendentes que você ainda pode observar. As duas metades importam: um cliente escrito contra a primeira metade sozinha vai, em algum momento, ler um saldo defasado e concluir que dinheiro desapareceu.
O princípio central
Uma obrigação é tornada durável no nosso banco de dados antes de a transação ser submetida ao ledger. O conjunto de saídas não gastas do ledger é a autoridade de liquidação; o banco de dados é o registro de intenção e a origem do modelo de leitura.
Duas consequências decorrem disso, e todo o resto desta página vem delas:
- Existe uma janela em que uma obrigação está registrada e ainda não está no ledger. Um
201significa registrada, não confirmada. - Leituras de saldo têm consistência eventual. Elas são calculadas a partir de índices atualizados depois da confirmação, e não de um número escrito no mesmo instante que a transação.
O que um observador vê, fase por fase
| Fase | Estado | Quem lê vê |
|---|---|---|
| Registrada | OPEN | A obrigação existe e é durável. Nada está no ledger. Ela não está em nenhum saldo. |
| Submetida | PENDING | A transação está com o processador. Legível por id. Ainda não está em um saldo. |
| Confirmada | PENDING → FINAL | Está no ledger. O modelo de leitura se atualiza logo depois, e nesse momento ela entra nos saldos. |
| Resolvida | FINAL | O ciclo de vida fechou e o desfecho da resolução está definido. Este é o único ponto em que 'liquidado' é uma afirmação verdadeira. |
Read-your-writes vale para um tipo de leitura
Ler uma obrigação pelo id é read-your-writes: é uma busca por chave e vai sempre refletir uma escrita que você acabou de fazer. Ler um saldo não é: é uma consulta a índice, e o índice é atualizado de forma assíncrona.
GET /v1/obligations/{obligation_id} # por chave, read-your-writes
GET /v1/accounts/{account_id}/balance # consulta a índice, consistência eventualFINAL é um estado de ciclo de vida, não uma afirmação de liquidação
FINAL significa que a obrigação não vai mudar de novo. Não significa que o valor se moveu. Uma obrigação pode estar FINAL com o desfecho da resolução ainda em branco, e pode estar FINAL tendo falhado.
liquidado = obligation.state == "FINAL"
and obligation.resolution_outcome == "SETTLED"Se você levar uma linha de código destes documentos, leve essa. Um filtro escrito como state == "FINAL" vai contar falhas como sucessos.
A defasagem é limitada na prática, e não por contrato
Uma transação confirmada chega a uma leitura de saldo depois de dois saltos assíncronos: o indexador a projeta, e o índice que ele escreve se propaga. Localmente os dois são abaixo de um segundo. Nenhum dos dois é um limite contratual, e não publicamos número para eles, porque nenhuma medição que fizemos mede aquilo que um número desses seria citado para prometer.
Projete considerando isso, e não contornando: consulte por id, use a linha do tempo da obrigação para histórico, e trate um saldo como uma visão que é correta, não instantânea.
Anomalias que você pode observar
Nomeá-las é deliberado. Um modelo de consistência sem lista de anomalias é ou mais forte que qualquer sistema real, ou menos honesto que um.
| Anomalia | Sintoma | O que você faz |
|---|---|---|
| Mutações concorrentes em um grupo | descartada em silêncio | Duas mutações seguidas na configuração do mesmo grupo podem devolver 201 as duas, e a que perde o gasto duplo subjacente é descartada da projeção. Serialize: consulte a composição do grupo entre as chamadas em vez de disparar as duas juntas. Depósitos em um grupo apenas leem a configuração, então não competem. |
| Defasagem de saldo | lançamento ausente | Uma transação recém-confirmada pode não estar na próxima leitura de saldo. Leia a obrigação pelo id para ter o estado definitivo. |
| Um 500 ao criar um grupo | repetir | A projeção é escrita como um grupo atômico, então uma falha persistente de banco aparece como 500 em vez de sucesso parcial. O grupo em si já está no ledger e a projeção é reconstruível a partir dele, então um 500 aqui quer dizer repetir, não investigar. |
| Uma escrita repetida depois de uma queda | seguro | Se cairmos entre aplicar uma operação e registrar a chave de idempotência dela, a sua repetição reexecuta. A segunda tentativa tenta gastar as mesmas saídas e o ledger rejeita a perdedora, então o resultado é um efeito, não dois. |
Existem outras anomalias cuja mitigação é nossa e não sua: uma obrigação que fica registrada e nunca é submetida depois de uma queda, e um crédito externo cujo processamento foi interrompido. As duas são detectadas por uma varredura de conciliação e resolvidas com ferramental de operação. Mencionamos porque uma lista que contivesse só os seus problemas seria uma lista incompleta, não porque você precisa programar para elas.
O que não afirmamos
- Nenhuma leitura de saldo fortemente consistente. Não existe flag que crie uma.
- Nenhuma garantia de ordenação entre entidades. Ordenação por entidade se sustenta; ordenação global não.
- Nenhuma entrega de evento exatamente uma vez. Eventos são ao menos uma vez e carregam ids determinísticos para você deduplicar. Veja Eventos e webhooks.