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.
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