Receba novidades do Hedhog no seu e-mail
Novos lançamentos, receitas e breaking changes — sem spam.
Provedores de Fila
O Hedhog processa tarefas em segundo plano — envio de e-mails, geração de relatórios, processamento de arquivos, tarefas agendadas — através do @hed-hog-pro/queue. Apenas o provedor Database está de fato implementado hoje. RabbitMQ e BullMQ existem como configurações e como um valor de enum provider, mas ainda não há um worker RabbitMQ ou BullMQ funcional por trás deles — escolher qualquer um dos dois nas configurações não fará as tarefas avançarem.
Isto não é um erro de configuração da sua parte se não funcionar; é o estado atual da biblioteca. Construa sobre o Database e trate as configurações de RabbitMQ/BullMQ como reservadas para uma versão futura, não como algo a depurar.
Status: ⚠️ Parcial — o provedor Database está totalmente implementado; RabbitMQ e BullMQ são configurações reservadas, ainda sem um provedor por trás.

Configuração Rápida
- Deixe
queue.providerdefinido comodatabase— é o único que funciona - Registre um handler de tarefa via
QueueModule.register({ handlers: {...} }) - Enfileire uma tarefa e confirme que uma linha
queue_jobaparece, e depois muda dependingparadone
Como Funciona (provedor Database)
- O código da aplicação enfileira uma tarefa, ex.:
QueueService.add('send-email', payload) - A tarefa é gravada como uma linha na tabela
queue_jobcomstatus = 'pending' - O
QueueWorkerProcessorconsulta essa tabela em intervalos, reivindica atomicamente um lote de tarefas via umupdateManycom lock otimista (para que múltiplas instâncias da API possam rodar workers sem processar a mesma tarefa em duplicidade) e invoca o handler registrado correspondente - Em caso de sucesso, a tarefa é marcada como concluída; em caso de falha, ela é reprocessada até
queue.default_max_attempts, depois marcada como falha - Tarefas presas em
processingalém dequeue.database.lock_timeout_seconds(ex.: um worker que travou no meio da tarefa) são automaticamente liberadas de volta para reprocessamento — você não precisa desbloqueá-las manualmente
Chaves de Configuração Reais
Diferente da maioria das outras receitas, as configurações de fila usam chaves separadas por ponto, não por hífen — não duvide de si mesmo se você ver queue.database.poll_interval_seconds em vez de queue-database-poll-interval-seconds, isso está correto.
Seleção de provedor e padrões
| Chave de configuração | Descrição |
|---|---|
queue.provider | Provedor ativo — deixe como database, o único que funciona |
queue.default_max_attempts | Reprocessamentos padrão antes de uma tarefa ser marcada como falha (padrão 3) |
queue.default_retry_delay_seconds | Atraso antes de reprocessar uma tarefa falha (padrão 300) |
queue.default_timeout_seconds | Tempo máximo que uma única execução de tarefa tem antes de ser considerada presa (padrão 900) |
Provedor Database (funcional)
| Chave de configuração | Descrição |
|---|---|
queue.database.enabled | Habilitar o provedor baseado em DB (padrão true) |
queue.database.poll_interval_seconds | Com que frequência o worker verifica novas tarefas (padrão 5) |
queue.database.batch_size | Tarefas reivindicadas por consulta (padrão 20) |
queue.database.lock_timeout_seconds | Por quanto tempo uma tarefa pode ficar em processing antes de ser tratada como obsoleta e liberada (padrão 300) |
Comportamento do worker (aplica-se independentemente do provedor)
| Chave de configuração | Descrição |
|---|---|
queue.worker.enabled | Se esta instância roda um worker — defina como false em instâncias que devem apenas enfileirar, nunca processar |
queue.worker.heartbeat_interval_seconds | Com que frequência o worker reporta que está vivo (padrão 30) |
queue.worker.dynamic_scope_enabled | Permitir que o conjunto de filas que este worker processa mude em tempo de execução sem reinício (padrão true) |
queue.worker.scope_refresh_interval_seconds | Com que frequência o worker reverifica seu escopo de filas atribuído (padrão 5) |
queue.worker.scope_drain_timeout_seconds | Período de tolerância para finalizar tarefas em andamento quando uma fila é removida do escopo (padrão 30) |
RabbitMQ / BullMQ (reservados, não implementados)
| Chave de configuração | Status |
|---|---|
queue.rabbitmq.enabled, queue.rabbitmq.url, queue.rabbitmq.exchange, queue.rabbitmq.default_queue | As configurações existem; nenhum código consumidor existe ainda |
queue.bullmq.enabled, queue.bullmq.redis_url | As configurações existem; nenhum código consumidor existe ainda |
Não suba RabbitMQ ou Redis esperando que o Hedhog os utilize — ainda não há nada do outro lado escutando.
Definindo Handlers de Tarefas
Registre os handlers no seu módulo NestJS:
import { QueueModule } from '@hed-hog-pro/queue';
@Module({
imports: [
QueueModule.register({
handlers: {
'send-email': SendEmailHandler,
'process-report': ProcessReportHandler,
},
}),
],
})
export class AppModule {}
Cada handler é uma classe com um método handle(job):
@Injectable()
export class SendEmailHandler implements JobHandler {
async handle(job: Job<{ to: string; subject: string; body: string }>) {
await this.mail.send(job.data);
}
}
Lance um NonRetryableError (do @hed-hog-pro/queue) em vez de um erro comum se uma falha não deve ser reprocessada — por exemplo, uma tarefa que falhou porque os dados de entrada eram permanentemente inválidos, não por causa de uma indisponibilidade transitória.
Escalando o Provedor Database
Como o worker usa uma reivindicação atômica (updateMany com um filtro de status como lock otimista), é seguro rodar múltiplas instâncias da API com queue.worker.enabled = true simultaneamente — elas não processarão a mesma tarefa em duplicidade. A vazão é limitada por queue.database.poll_interval_seconds e queue.database.batch_size; reduza o intervalo de consulta ou aumente o tamanho do lote para volume maior, ao custo de mais carga de consulta frequente no PostgreSQL.
Verifique se Funcionou
- Enfileire uma tarefa de teste e confirme que uma linha aparece em
queue_jobcomstatus = 'pending', e depois muda paradonedentro dequeue.database.poll_interval_seconds - Force um handler a lançar uma exceção uma vez e confirme que a tarefa é reprocessada em vez de desaparecer, até
queue.default_max_attempts
Solução de Problemas
| Sintoma | Causa provável |
|---|---|
| As tarefas são enfileiradas mas nunca rodam | queue.worker.enabled está false em todas as instâncias em execução |
queue.provider definido como rabbitmq ou bullmq e nada acontece | Esperado — nenhum dos dois provedores está implementado; volte para database |
Uma tarefa fica presa em processing indefinidamente | O worker que a reivindicou travou antes que queue.database.lock_timeout_seconds decorresse — ele se auto-liberará após esse timeout, não antes |
| A mesma tarefa processada duas vezes | Não deveria acontecer com o lock otimista do provedor Database — se você ver isso, verifique se há um handler personalizado que não é idempotente, em vez da camada de fila em si |