Adios
BlogE-commerce com Next.js

E-commerce com Next.js

Como gerenciar estoque e invalidação de cache em uma loja Next.js

Evite vendas acima do estoque com estoque transacional, reservas, webhooks idempotentes, tags de cache Next.js, invalidação específica e testes de concorrência.

Equipe AdiosAtualizado 17 de julho de 20268 min de leitura

Estoque é uma transação, não um valor em cache. O cache informa o que estava disponível recentemente; somente a gravação na fonte de verdade pode prometer a última unidade.

Definir disponível, reservado e vendido

Trail Supply tem dois Alpine Shell azuis de tamanho médio. onHand é a quantidade física, reserved é o que está temporariamente reservado por checkouts ativos e sold pertence a pedidos confirmados. A disponibilidade deriva desses estados duráveis, em vez de ser um número independente que possa ficar inconsistente.

Defina quando a reserva começa, quanto dura e qual evento a confirma ou libera. Reservar ao adicionar ao carrinho costuma ser cedo demais; reservar no Checkout pode servir a estoques limitados; reservar no pagamento exige uma política para compradores simultâneos.

Faça a mudança de estoque atômica

Uma sequência de leitura seguida de gravação permite que duas requisições vejam a mesma última unidade. Use transação, bloqueio de linha, atualização condicional ou outra operação atômica compatível com o armazenamento. A gravação só tem sucesso se ainda houver estoque não reservado suficiente.

Imponha quantidades não negativas com restrições no banco quando possível. Registre reserva, variante, quantidade, proprietário ou pedido pendente, criação, expiração e status na mesma transação que altera a disponibilidade.

const reserved = await db.inventory.updateMany({
  where: {
    variantId,
    available: { gte: quantity },
  },
  data: {
    available: { decrement: quantity },
    reserved: { increment: quantity },
  },
});

if (reserved.count !== 1) {
  return { error: "Insufficient stock" };
}

Expirar deliberadamente as reservas

Armazene a expiração e execute uma tarefa agendada de recuperação que libere reservas ativas cuja Checkout Session não possa mais concluir. A liberação deve ser idempotente: uma reserva já confirmada ou liberada não deve mudar.

Eventos atrasados precisam de uma política. Se o pagamento concluir após a expiração local, concilie o estado do provedor e do processamento do pedido em vez de recriar estoque ou cancelar um pedido pago sem verificação. Algumas lojas permitem pedidos pendentes por falta de estoque; outras reembolsam. Implemente a decisão do produto.

Colocar leituras do catálogo em cache, não decisões transacionais

Com Cache Components habilitado, armazene a apresentação de produtos e categorias com use cache, cacheLife adequado e tags de produto, variante e categorias afetadas. A disponibilidade exibida só pode estar ligeiramente desatualizada se o checkout fizer uma validação com os dados oficiais.

Mantenha alterações de carrinho e estoque fora de caches públicos compartilhados. Carrinhos específicos de usuários precisam de processamento a cada requisição ou cache privado. Nunca armazene uma promessa de estoque vinculada à sessão com uma chave cujo conteúdo outro comprador possa receber.

export async function getProduct(slug: string) {
  "use cache";
  cacheLife("minutes");
  cacheTag("product:" + slug);
  return loadProductView(slug);
}

Invalidar o menor conjunto correto

Após alterar estoque ou preço, invalide o produto e cada categoria que exiba o valor alterado. updateTag permite ao usuário da Server Action ver a própria gravação; revalidateTag com um perfil adequado serve ao conteúdo que pode mostrar dados antigos durante a atualização.

Não limpe todas as páginas da loja em cache quando uma jaqueta azul média mudar. Invalidações amplas aumentam a carga e dificultam entender o cache. Centralize a criação das tags para que publicação, webhooks e ações administrativas usem os mesmos nomes.

Conciliar eventos do armazém e dos pagamentos

Registre IDs de eventos externos antes de alterar o estoque. Ajustes do armazém, cancelamentos, reembolsos e pagamentos concluídos podem se repetir ou chegar fora de ordem. Normalize cada evento como transição local de estoque e rejeite transições incompatíveis com o estado atual.

Mantenha um registro de movimentos somente com acréscimos ou um histórico de auditoria suficiente para explicar o total. Corrigir a quantidade atual sem o histórico de reservas e pedidos é difícil após uma falha de provedor ou implantação.

Testar disputa por estoque e recuperação sob carga

Envie muitas reservas simultâneas para as últimas duas unidades e verifique se no máximo duas têm sucesso. Interrompa um worker, repita um pagamento, expire uma reserva, entregue uma conclusão atrasada e reconstrua a visão do produto em cache. Verifique as invariantes do banco e os resultados visíveis aos clientes.

Execute esses testes contra a compilação de produção em uma prévia Adios. Os logs de execução revelam disputas por recursos e erros de webhook, enquanto banco e segredos obrigatórios ficam explícitos no manifesto. Promova a versão após a rota de saúde e os testes básicos de estoque passarem.

Todos os artigos