Logotipo Hedhog

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.

Tabela queue_job consultada pelo QueueWorkerProcessor, com RabbitMQ e BullMQ mostrados como ainda-não-implementados

Configuração Rápida

  1. Deixe queue.provider definido como database — é o único que funciona
  2. Registre um handler de tarefa via QueueModule.register({ handlers: {...} })
  3. Enfileire uma tarefa e confirme que uma linha queue_job aparece, e depois muda de pending para done

Como Funciona (provedor Database)

  1. O código da aplicação enfileira uma tarefa, ex.: QueueService.add('send-email', payload)
  2. A tarefa é gravada como uma linha na tabela queue_job com status = 'pending'
  3. O QueueWorkerProcessor consulta essa tabela em intervalos, reivindica atomicamente um lote de tarefas via um updateMany com 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
  4. 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
  5. Tarefas presas em processing além de queue.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çãoDescrição
queue.providerProvedor ativo — deixe como database, o único que funciona
queue.default_max_attemptsReprocessamentos padrão antes de uma tarefa ser marcada como falha (padrão 3)
queue.default_retry_delay_secondsAtraso antes de reprocessar uma tarefa falha (padrão 300)
queue.default_timeout_secondsTempo máximo que uma única execução de tarefa tem antes de ser considerada presa (padrão 900)

Provedor Database (funcional)

Chave de configuraçãoDescrição
queue.database.enabledHabilitar o provedor baseado em DB (padrão true)
queue.database.poll_interval_secondsCom que frequência o worker verifica novas tarefas (padrão 5)
queue.database.batch_sizeTarefas reivindicadas por consulta (padrão 20)
queue.database.lock_timeout_secondsPor 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çãoDescrição
queue.worker.enabledSe esta instância roda um worker — defina como false em instâncias que devem apenas enfileirar, nunca processar
queue.worker.heartbeat_interval_secondsCom que frequência o worker reporta que está vivo (padrão 30)
queue.worker.dynamic_scope_enabledPermitir 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_secondsCom que frequência o worker reverifica seu escopo de filas atribuído (padrão 5)
queue.worker.scope_drain_timeout_secondsPerí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çãoStatus
queue.rabbitmq.enabled, queue.rabbitmq.url, queue.rabbitmq.exchange, queue.rabbitmq.default_queueAs configurações existem; nenhum código consumidor existe ainda
queue.bullmq.enabled, queue.bullmq.redis_urlAs 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_job com status = 'pending', e depois muda para done dentro de queue.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

SintomaCausa provável
As tarefas são enfileiradas mas nunca rodamqueue.worker.enabled está false em todas as instâncias em execução
queue.provider definido como rabbitmq ou bullmq e nada aconteceEsperado — nenhum dos dois provedores está implementado; volte para database
Uma tarefa fica presa em processing indefinidamenteO 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 vezesNã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