Introdução: por que seu servidor dorme quando deveria trabalhar
\n\nImagine: o usuário clica no botão "Enviar relatório" e a página trava por 30 segundos. O servidor gera um PDF, compacta imagens e envia um e-mail — tudo de forma síncrona. Familiar? Se sim, você caiu na armadilha do código bloqueante.
\n\nNeste artigo, vamos entender como filas e tarefas em segundo plano com TypeScript resolvem esse problema. Você aprenderá a transferir trabalhos pesados para processos em segundo plano, sem perder o controle sobre erros e escalabilidade. O material foi escrito para desenvolvedores que já conhecem Node.js e querem levar seu projeto para o próximo nível.
\n\nFalaremos sobre as bibliotecas Bull e BullMQ, abordaremos o RabbitMQ e mostraremos exemplos reais de código em TypeScript. Vamos lá!
O que é uma fila de tarefas e por que ela é necessária
\n\nFila de tarefas (task queue) é um mecanismo que separa a solicitação do usuário de sua execução. Em vez de processar a operação diretamente no manipulador HTTP, enviamos a tarefa para uma fila, e um worker em segundo plano a coleta e executa de forma assíncrona.
\n\nCenários típicos de uso
\n- \n
- Envio de e-mails e notificações push \n
- Geração de PDF, imagens, vídeos \n
- Parsing de dados e web scraping \n
- Processamento de pedidos em lojas online \n
- Cálculos em massa e relatórios \n
Sem filas, sua aplicação corre o risco de cair sob carga. Com elas, você obtém tolerância a falhas (se um worker cair, a tarefa não será perdida) e escalabilidade (você pode executar 10 workers em vez de um).
\n\nBull e BullMQ: filas poderosas para Node.js
\n\nBull é a biblioteca mais popular para trabalhar com filas no ecossistema Node.js. Ela é baseada em Redis e suporta TypeScript nativamente. BullMQ é sua sucessora, mais moderna, com suporte a sandboxes (processos isolados) e gerenciamento avançado.
\n\nInstalação e configuração básica
\nnpm install bullmq ioredis\nnpm install -D @types/bull\n\nVamos criar uma fila e um worker em TypeScript:
\n\n// queue.ts\nimport { Queue } from 'bullmq';\n\nconst connection = {\n host: 'localhost',\n port: 6379,\n};\n\nexport const emailQueue = new Queue('email', { connection });\n\n// worker.ts\nimport { Worker } from 'bullmq';\nimport { sendEmail } from './emailService';\n\nconst worker = new Worker('email', async job => {\n const { to, subject, body } = job.data;\n await sendEmail(to, subject, body);\n console.log(`E-mail enviado para ${to}`);\n}, { connection });\n\nworker.on('completed', job => {\n console.log(`Tarefa ${job.id} concluída`);\n});\n\nworker.on('failed', (job, err) => {\n console.error(`Tarefa ${job.id} falhou: ${err.message}`);\n});\n\nAgora, em qualquer lugar da aplicação, podemos adicionar uma tarefa:
\n\nimport { emailQueue } from './queue';\n\nawait emailQueue.add('send-welcome', {\n to: 'user@example.com',\n subject: 'Bem-vindo!',\n body: 'Obrigado por se registrar...'\n});\n\nSimples, não é? Mas isso é apenas o começo. O BullMQ oferece muito mais possibilidades.
\n\nRecursos avançados do BullMQ
\n- \n
- Tentativas repetidas — se uma tarefa falhar, ela pode ser reiniciada automaticamente após N segundos. \n
- Atraso na execução — adiar uma tarefa para um horário específico. \n
- Prioridades — tarefas urgentes são processadas primeiro. \n
- Eventos — você pode se inscrever para progresso, conclusão, erros. \n
- Sandboxes — execução de código em um processo isolado (segurança + limpeza). \n
Exemplo com repetições e atraso:
\n\nawait emailQueue.add('send-invoice', {\n invoiceId: 123,\n email: 'client@example.com'\n}, {\n attempts: 5,\n backoff: { type: 'expon