Adios
BlogNext.js SaaS

Next.js SaaS

Como executar tarefas em segundo plano e webhooks confiáveis em um SaaS Next.js

Projete tarefas duráveis, webhooks verificados, novas tentativas, idempotência, prazos, estados de falha e trabalho observável em segundo plano para um SaaS Next.js.

Equipe AdiosAtualizado 17 de julho de 20268 min de leitura

Uma requisição não é o lugar adequado para trabalho que leva minutos, depende de um provedor instável ou precisa sobreviver ao reinício de um processo. O estado durável deve existir além da requisição.

Identificar o trabalho que deve sair da requisição

Transfira importações, exportações, relatórios, processamento de mídia, e-mails em massa, sincronização com provedores e outros trabalhos demorados para tarefas duráveis. A requisição deve validar a intenção, gravar a tarefa e retornar um identificador para a interface acompanhar o progresso.

Nem toda tarefa assíncrona precisa de um serviço separado no primeiro dia. Mas precisa de estado durável, responsável, contrato de execução e caminho de recuperação. Uma promise não aguardada em um Route Handler pode desaparecer quando o processo termina, sem deixar um registro confiável para o usuário.

Modelar o ciclo de vida da tarefa

Registre ID estável, tipo, proprietário, referência à entrada validada, status, quantidade de tentativas, horário da próxima execução, referência ao resultado e erro sanitizado. Use estados como queued, running, succeeded, failed e canceled. Uma concessão temporária ou sinal periódico de atividade evita que dois workers mantenham silenciosamente a mesma tentativa para sempre.

Armazene dados grandes de entrada e saída fora do registro da fila quando apropriado. A tarefa deve referenciar objetos duráveis e verificar novamente a autorização ou propriedade atual antes de publicar o resultado.

type JobState =
  | "queued"
  | "running"
  | "succeeded"
  | "failed"
  | "canceled";

type Job = {
  id: string;
  tenantId: string;
  type: string;
  state: JobState;
  attempts: number;
  runAfter: Date;
};

Tornar a execução idempotente

Um worker pode falhar depois de uma ação externa ter sucesso e antes de registrar o sucesso localmente. Projete cada etapa para permitir repetição segura. Use chaves de negócio únicas, chaves de idempotência dos provedores, upserts e checkpoints registrados, em vez de presumir entrega exatamente uma vez.

Separe a identidade da tarefa de cada tentativa. As novas tentativas devem compartilhar a mesma tarefa de negócio e registrar evidências próprias. Assim, a interface mostra o que ocorreu sem criar vários e-mails ou exportações indistinguíveis.

Limitar novas tentativas e chamadas externas

Defina prazos de conexão e resposta para os provedores. Repita timeouts transitórios, limites de taxa e falhas temporárias com espera progressiva e variação aleatória. Não repita indefinidamente entradas inválidas, autorizações revogadas ou rejeições permanentes do provedor.

Ao esgotar o limite de tentativas, coloque a tarefa em um estado visível de falha e gere alertas conforme sua importância. Preserve contexto suficiente para agir sem registrar credenciais ou dados privados enviados.

  • —Classificar erros antes de tentar novamente.
  • —Limite o número de tentativas e o tempo total.
  • —Distribua as novas tentativas com variação aleatória.
  • —Permita novas tentativas manuais somente quando for seguro repetir a operação.

Proteger webhooks recebidos

Receba eventos do provedor em um Route Handler, verifique a assinatura sobre o corpo bruto, rejeite requisições inválidas ou antigas conforme o protocolo do provedor e registre o ID do evento antes de executar trabalho caro. Retorne sucesso rapidamente assim que o encaminhamento durável estiver concluído.

Use uma restrição de unicidade para deduplicar entregas. Associe o evento do provedor a um tenant ou conta local por metadados confiáveis ou IDs armazenados do provedor, não por um campo arbitrário de tenant no payload.

Mostrar o progresso real aos usuários

Enviar uma tarefa não significa concluí-la. Retorne seu ID e mostre na aplicação se está na fila ou em execução. Atualize por navegação no servidor, polling ou um canal em tempo real adequado ao produto. Mostre falhas e cancelamentos em vez de deixar um indicador de carregamento indefinidamente.

Proteja downloads de resultados com as mesmas verificações de propriedade da requisição inicial. Faça os arquivos gerados expirarem quando apropriado e separe as explicações ao usuário dos detalhes internos do erro.

Testar interrupções e entregas duplicadas

Pare um worker no meio de uma etapa, reinicie-o, entregue o mesmo webhook duas vezes, atrase um provedor além do timeout, esgote as tentativas e remova o acesso do usuário antes da conclusão. Confirme que a operação continua segura e que o estado final é compreensível.

Teste implantações com tarefas em andamento. Os workers devem concluir, liberar ou repetir com segurança o trabalho sob concessão temporária, conforme o projeto. As migrações de esquema devem continuar compatíveis com tarefas enfileiradas pela versão anterior.

Operar tarefas e workflows junto da aplicação

A Adios executa processos persistentes e workflows inspecionáveis com gatilhos, etapas, esperas, aprovações e histórico. Mantenha as requisições Next.js focadas em validação e encaminhamento durável e deixe a execução com novas tentativas para o worker ou workflow.

Implante a configuração e as referências a segredos junto do código-fonte, inspecione separadamente os logs da aplicação e dos workflows e use controles de saúde nos serviços que recebem tráfego. Assim, a versão usada pelos clientes permanece estável, enquanto falhas em segundo plano têm suas próprias evidências e caminhos de recuperação.

env:
  DATABASE_URL: secret://DATABASE_URL
  EMAIL_API_KEY: secret://EMAIL_API_KEY

runtime:
  name: node@24
  port: 3000
  health_path: /api/health
Todos os artigos