O que é Ledger e por que precisa de Idempotência?
Ja ouviu falar sobre idempotência? Não? Certeza que você usa e só não sabe que é o conceito por trás da tecnologia do seu software, produto, empresa, etc.
No nosso post anterior, discutimos o que é um ledger e por que é essencial aprender sobre ele. Exploramos suas origens, como funciona e sua importância em instituições financeiras. Agora, vamos nos aprofundar em um conceito crítico na construção de ledgers robustos e confiáveis: a idempotência.
O que é Idempotência?
Idempotência é a propriedade de certas operações que podem ser aplicadas múltiplas vezes sem alterar o resultado além da aplicação inicial. Em outras palavras, se uma operação é idempotente, realizá-la uma vez ou várias vezes terá o mesmo efeito. Esse conceito é crucial em sistemas distribuídos, APIs e transações financeiras para evitar processamento duplicado.
Por que a Idempotência é Importante em um Ledger?
Prevenção de Transações Duplicadas: Em um ledger, a idempotência garante que, se uma transação for acidentalmente enviada mais de uma vez, ela não será registrada várias vezes, o que poderia levar a saldos incorretos.
Consistência: A idempotência ajuda a manter a consistência e integridade dos registros financeiros, o que é vital para auditorias e conformidade regulatória.
Tratamento de Erros: Os sistemas podem reexecutar operações com segurança sem o risco de aplicar a mesma transação várias vezes, tornando o sistema mais robusto e tolerante a falhas.
Implementando Idempotência em um Ledger
Para ilustrar como implementar a idempotência em um ledger, vamos atualizar nosso exemplo anterior para incluir um ID de transação. Esse ID de transação será usado para garantir que cada transação seja registrada apenas uma vez.
Defina a estrutura do ledger no MongoDB:
{
_id: ObjectId("60c72b2f9b1d8e4d2f507d3a"),
date: ISODate("2023-06-13T12:00:00Z"),
description: "Depósito",
amount: 1000.00,
balance: 1000.00,
transactionId: "abc123"
}
Note que adicionamos o campo transactionId. Esse campo será o responsável por adicionar idempotência ao LedgerEntry.
Função para adicionar uma nova entrada no ledger e calcular o saldo com idempotência:
const { MongoClient } = require('mongodb');
async function addTransaction(description, amount, transactionId) {
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
try {
await client.connect();
const database = client.db('finance');
const ledger = database.collection('ledger');
// Verifica se a transação já existe
const existingTransaction = await ledger.findOne({ transactionId: transactionId });
if (existingTransaction) {
console.log('Transação já existe:', existingTransaction);
return;
}
// Obtém a última entrada no ledger
const lastEntry = await ledger.find().sort({ date: -1 }).limit(1).toArray();
const lastBalance = lastEntry.length > 0 ? lastEntry[0].balance : 0;
// Calcula o novo saldo
const newBalance = lastBalance + amount;
// Cria uma nova entrada no ledger
const newEntry = {
date: new Date(),
description: description,
amount: amount,
balance: newBalance,
transactionId: transactionId
};
// Insere a nova entrada no ledger
await ledger.insertOne(newEntry);
console.log('Transação adicionada com sucesso:', newEntry);
} finally {
await client.close();
}
}
// Exemplo de uso
addTransaction('Depósito', 500.00, 'unique-transaction-id-001');
Como manter o mesmo transactionId?
Importante: seu sistema precisa garantir que o transactionId sempre será criado conforme o esperado para garantir que a transação seja única. Como fazer isso?
Vamos supor que você possui um sistema de pagamentos de funcionários e você não podem duplicar o pagamento dos mesmos. Para isso, você pode ter um model auxiliador que inicia um pagamento, um PaymentIntent. Esse PaymentIntent possui o seguinte modelo
{
_id: ObjectId("60c72b2f9b1d8e4d2f508d82"),
taxID: '12345678990', // cpf do funcionário
description: "Salário",
amount: 3000.00,
status: 'PENDING',
transactionId: '456',
companyId: '123',
}
Uma vez que você chamar a função de criação da entra no ledger você pode montar o transactionId combinando: id empresa + paymentIntent transactionId. Assim, toda vez que você for processar o pagamento para aquele PaymentIntent sempre será montado o mesmo transactionId garantindo que o Ledger consiga identificar aquela entrada.
Conclusão
Implementar a idempotência no seu sistema de ledger é crucial para manter registros financeiros precisos e confiáveis. Ao garantir que cada transação seja registrada apenas uma vez, você pode prevenir entradas duplicadas e manter a integridade dos seus dados.
Como vimos, a idempotência não é apenas um detalhe técnico, mas um princípio fundamental que ajuda a construir sistemas robustos e tolerantes a falhas. No nosso próximo post, exploraremos tópicos mais avançados na gestão de ledgers e como lidar com outros desafios, como concorrência e consistência eventual.
Sigam-me no Twitter
Se gosta e quer apoiar o meu trabalho seja meu patreon
Quer alavancar sua carreira? Comece agora com minha mentoria pelo link
https://mentor.daniloassis.dev
Veja mais em https://linktr.ee/daniloab
Foto de The Creativv na Unsplash
Vejo vários problemas, como uso do mongodb, número flutuante para representação monetária e operações não atômicas (até porque seja pedir muitos do mongo…)
Falar que mongo é um problema é muito vago. Usamos em prod na Woovi e nao temos problemas algum. Quanto a flutuante é so um exemplo breve em um blog post. A maioria das apis em produção utilizam float, nao que eu indique, tanto que na Woovi usamos centavos \o/