Saltar para o conteúdo principal

Porque é que as novas tentativas de compra criam direitos duplicados e como testá-las

Original Persistium gráfico de compra mostrando uma intenção, um registro durável, e uma decisão de direito replay-seguro.

Como modelar a intenção de compra, resultados de commit desconhecidos, repetições e unicidade de direito para que uma compra possa ser segura e repetida sem conceder duas vezes.

Uma repetição não é uma segunda decisão de compra

Os fluxos de compra falham no espaço entre um evento de pagamento externo e uma concessão no jogo. Um recibo pode chegar duas vezes. Uma solicitação de rede pode parar após o estado comprometido do servidor, mas antes de o cliente receber a resposta. Um processo pode falhar após reservar uma transação, mas antes de conceder a moeda. Ao reiniciar, a ação mais segura pode ser tentar novamente o trabalho que foi interrompido. Se o sistema tratar cada repetição como permissão para conceder, os direitos duplicados são uma consequência normal da recuperação.

A distinção útil é intenção versus subvenção. Intenção é o pedido para obter um produto específico sob uma identidade de transação específica. Grant é o resultado de jogo durável: propriedade de direitos, um delta de moeda, um item de inventário, ou um período de assinatura. A mesma intenção pode ser entregue, interrogada, reexperimentada ou reenviada muitas vezes. Deve ainda resolver uma decisão de concessão.

Este é um padrão de engenharia, não uma garantia específica da plataforma. Diferentes lojas, provedores de pagamento e backends de jogo expõem diferentes comportamentos de recebimento, reconhecimento e reembolso. Não assuma que um recibo prove uma concessão, ou que um reconhecimento prove que o jogador viu um item. Construa o registro do lado do servidor para que o jogo possa indicar o que sabe e recuperar com segurança quando um resultado externo estiver incompleto ou atrasado.

Dar a cada intenção de compra uma chave estável

Uma chave de idempotência liga tentativas de entrega repetidas a uma decisão. Ela pode derivar de um identificador de transação de plataforma confiável quando esse identificador está disponível e verificado, ou pode ser emitida por um servidor antes de uma compra começar e ser vinculada posteriormente a informações de recebimento confiáveis. A chave deve ser estável entre repetições. Criando uma nova chave aleatória cada vez que o cliente pressiona “restore” simplesmente cria múltiplas transações que acontecem para parecer semelhante.

Armazene contexto suficiente com a chave para rejeitar erros: alcance do jogador ou da conta, identidade do produto, quantidade esperada ou forma de direito, canal de origem, tempo recebido, estado de verificação, e um estado como pendente, comprometido, rejeitado, ou necessidade de revisão. Mantenha o material de recebimento sensível fora de registros comuns. Se as cargas úteis do provedor cru precisam de retenção curta para um fluxo de recuperação verificado, protegê-los separadamente e fazer seu acesso deliberado.

O modelo de dados também precisa de um limite de unicidade. Para um direito não consumível, a unicidade pode ser a conta mais o ID do produto. Para a moeda, a unicidade é normalmente a entrada no livro de registos ou a transação de concessão em vez do saldo atual. Para os consumíveis, um identificador de transação confiável pode ser único, mesmo quando o ID do produto se repete. Defina a chave antes de codificar a política de repetição; caso contrário, dois subsistemas podem deduplicar- se contra identidades incompatíveis.

Modelar o resultado desconhecido da persistência

O resultado difícil não é um sucesso limpo ou uma falha limpa. É “desconhecido”: o cliente não sabe se o servidor cometeu a concessão. Um tempo- limite, o reset da conexão, o reinício do processo ou a interrupção do serviço podem produzir este estado. O comportamento seguro do cliente é pedir o status da transação ou tentar novamente a mesma intenção. O comportamento seguro do servidor é procurar essa intenção e retornar a decisão durável em vez de aplicar outra mutação.

Não torne o estado de exibição do cliente autorizado. Um spinner desaparecendo, um cache de recibo local, ou uma mudança de equilíbrio otimista pode melhorar a experiência, mas ele não pode decidir se a conta possui um direito. A autoridade do servidor significa que o servidor verifica a transação aceita de acordo com o limite de confiança do produto, compromete o registro durável uma vez e retorna o estado atual quando perguntado novamente.

Diagrama de sequência de compra original mostrando tentativas de entrega repetidas convergindo em um registro de registro e uma decisão de direito.
Repetições e redelivery de recebimento resolver contra a mesma intenção de compra durável em vez de criar novos subsídios.

A sequência deverá tornar visível a política de completamento parcial. Por exemplo: receber intenção, validar provas de compra fidedignas, criar ou carregar o registo de registo duradouro, cometer a mutação de direito ou moeda, marcar o registo concedido, reconhecer a entrega externa quando apropriado, em seguida, devolver o resultado. Se o processo parar entre duas etapas, um trabalhador de recuperação ou posterior consulta de estado poderá retomar a partir do registo durável. A ordenação exacta depende do fornecedor externo e da arquitectura do jogo, mas a identidade de concessão única não.

Proteger os direitos e as variações monetárias

Uma chave de idempotência impede o replay de uma intenção; ela não corrige automaticamente todos os efeitos colaterais. Defina os invariantes que uma subvenção deve preservar. Um direito não consumível aparece no máximo uma vez para a conta e o produto. Uma bolsa de moeda tem um registro com uma chave de transação, um delta conhecido, e um saldo resultante que corresponde à soma dos itens válidos. Os subsídios de inventário obedecem às regras de pilha, capacidade e definição de itens. Um período de assinatura não se estende duas vezes porque o resultado da confirmação correu duas vezes.

Faça a verificação invariante parte da mesma operação durável que compromete a concessão. Uma leitura seguida de uma escrita posterior pode correr sob entrega concorrente. Dois trabalhadores podem tanto observar “não pertence” e ambos conceder. Use armazenamento transacional, semântica de comparação e ajuste, um caminho de mutação de conta serializado, ou outro primitivo de concorrência explícita adequado para o armazenamento de dados. A propriedade importante é que a decisão e seu marcador não podem ser ganhos independentemente por duas tentativas.

Para jogos com um tempo de execução na memória, distinga o sucesso durável da apresentação. O servidor pode atualizar o saldo visível de um jogador após a entrada do livro de registros durável comprometer, mas a atualização visível não é a prova. Ao reconectar ou reiniciar, reconstrua o estado apresentado do registro de conta durável. Isso torna uma resposta tardia ao cliente inconveniente, em vez de financeiramente insegura.

Teste trava, reinicia e redelivery deliberadamente

Comece com um cenário determinístico. Crie uma conta, um produto, um saldo inicial conhecido ou um conjunto de direitos, e uma chave de transação estável. Execute o fluxo, então injete uma falha após cada limite nomeado: após a aceitação do recibo, após a criação do livro de registro, após a mutação do direito, após a marcação do status, após o reconhecimento externo, e após a resposta ser preparada. Reinicie o trabalhador ou processo relevante, tente novamente a mesma chave e assevere o estado final durável.

O resultado esperado deve ser específico. Uma nova tentativa pode retornar “já concedido” com o resultado original, retomar uma operação pendente, rejeitar uma carga útil desigualizada, ou manter um registro para revisão. Ela não deve adicionar um segundo item de inventário, aplicar um delta de segunda moeda, ou ocultar o estado desconhecido com um sucesso fabricado. Capture a classificação no resultado do teste para que um refactor posterior não possa transformar uma retenção intencional em uma duplicata acidental.

Use a redelivery do recibo no mesmo cenário. Entregue a transação confiável exata duas vezes, em seguida, entregue-a após uma reinicialização, em seguida, entregue-a ao lado de uma repetição duplicada do cliente. O registro resultante e o estado da conta devem ser idênticos ao caso de entrega única. Se o produto permitir a repetição de compras, execute a mesma sequência com duas identidades de transação genuinamente distintas para provar que o sistema não se deduplica com o ID do produto sozinho.

Mantenha os limites honestos

O teste pode provar apenas as interações que você executa. Uma resposta simulada do provedor pode validar sua máquina de estado, mas não é evidência de que cada borda do provedor de produção se comporta exatamente da mesma maneira. Um teste executável contra uma caixa de areia pode adicionar confiança para essa integração, mas ainda tem condições operacionais diferentes de uma loja ao vivo. Grave se um cenário usa uma simulação, adaptador local, caixa de areia ou ambiente de provedor verificado.

O limite de confiança também deve ser claro. Um cliente não deve enviar uma quantidade arbitrária, ID do produto ou bandeira “verificada” e receber uma subvenção. As entradas não são confiáveis até que o servidor as valide contra a configuração relevante e a evidência de compra. Se a validação não puder terminar, mantenha a intenção pendente ou rejeite- a com uma categoria recuperável. Não deixe que uma fila de repetição se torne um bypass em torno da verificação.

A privacidade aplica-se a esta disciplina de testes. Os dispositivos devem usar dados sintéticos de transação. Os registos devem referenciar um identificador de teste seguro, não um nome de conta ou recibo bruto. Um incidente de produção pode exigir provas restritas, mas o conjunto de testes de rotina nunca deverá tornar-se um segundo armazém de dados de pagamento.

Lista de verificação prática

  • Separe uma intenção de compra estável da concessão posterior lado do jogo.
  • Use uma chave de idempotência em intervalos de tempo, repetições, reinicialização e redelivery de recibo.
  • Amarre a chave para a conta, forma do produto ou direito, e contexto de fonte confiável.
  • Defina estados duráveis como pendente, comprometido, rejeitado e revisão de necessidades.
  • Imponha a unicidade do direito e invariantes de divisas dentro do mesmo limite de concorrência que a subvenção.
  • Injete falhas após cada transição de estado, então reinicie e tente novamente a mesma intenção.
  • Teste a entrega duplicada e as compras legítimas repetidas separadamente.
  • Relatar resultados desconhecidos honestamente; não transformar um tempo limite em um sucesso inventado.
  • Mantenha dispositivos de recepção e registros de teste sintéticos e editados.

Perguntas mais frequentes

Uma identificação de recibo única é suficiente para a idempotência?

Ele pode ser um componente útil quando o servidor pode verificar que a identidade de recebimento é confiável e explorá-lo corretamente. Ainda é importante armazenar a decisão de concessão resultante, a política de descompatibilidade e estado de recuperação. Um sistema pode receber o mesmo identificador repetidamente, recebê-lo tarde, ou recebê-lo com uma carga útil que não corresponde ao contexto de produto armazenado. O registro durável é o que torna esses casos inspeccionáveis.

Deve um cliente tentar novamente automaticamente após um intervalo?

Normalmente, ele deve tentar de novo a resolução de status usando a mesma identidade de intenção, com backoff limitado e feedback do usuário claro. Se ele deve reenviar evidência de compra externa depende do provedor e do design de verificação. O comportamento inseguro está silenciosamente criando um novo pedido de compra ou aplicando um subsídio local porque a resposta original foi perdida.

Em que medida os consumíveis diferem dos direitos permanentes?

Os direitos permanentes geralmente deduplicam por conta e produto. Os consumíveis podem permitir que o mesmo produto seja comprado muitas vezes, de modo que o limite de singularidade deve incluir uma identidade de transação ou sequência de registro em vez de ID do produto sozinho. Ambos ainda precisam de uma única bolsa durável para cada intenção aceita.

O que o Persistium reivindica aqui?

Persistium está em desenvolvimento. Esta nota explica a integridade amplamente aplicável e padrões de projeto de teste; ele não reivindica um produto de compra pública, certificação de plataforma, histórico de incidentes do cliente, ou um serviço hospedado. Sua direção Continuidade está interessada no mesmo tipo de evidência limitada e disciplina de recuperação segura.

Sistema relacionadoExplore Persistium