Infraestrutura & Ferramentas

Filas

Sistema de queues e workers.

Filas (Queue)

Sistema de filas 100% nativo do illuminate/queue — driver de banco de dados (tabela jobs na conexão iam). Use para tirar trabalho pesado (e-mails, relatórios, integrações) do caminho síncrono da request, sem travar o usuário.

Como funciona

Requisição web
    └── MeuJob::dispatch($dados)
            └── insere registro na tabela jobs (conexão iam)

php artisan queue:work (processo separado, em background)
    └── lê jobs da tabela jobs
        └── instancia MeuJob e chama handle()
            ├── sucesso → remove da tabela jobs
            └── falha   → tenta novamente (até $tries vezes)
                          após esgotar → move para failed_jobs

Criando um Job

Gere com php artisan make:job e implemente ShouldQueue — não há classe base própria do MAD, é o Job padrão do Laravel:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ProcessarPedidoJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries   = 3;    // tentativas antes de ir para failed_jobs
    public int $timeout = 120;  // segundos máximos de execução

    public function __construct(public int $pedidoId) {}

    public function handle(): void
    {
        $pedido = Pedido::findOrFail($this->pedidoId);
        $pedido->processar();
    }
}

Propriedades comuns do Job

Propriedade Padrão Descrição
$tries 1 (sobrescrito por --tries do worker) Tentativas antes de ir para failed_jobs
$timeout 60 Segundos máximos — worker mata o processo se ultrapassar
$backoff — Array de segundos de espera entre tentativas ([10, 30, 90]) ou um int fixo
$queue default Fila onde o job é colocado (também via ->onQueue('nome') no dispatch)

Disparando Jobs

// Dispatch simples — fila default
ProcessarPedidoJob::dispatch($pedido->id);

// Dispatch em fila específica
EnviarRelatorioJob::dispatch($dados)->onQueue('reports');

// Dispatch com atraso
NotificarClienteJob::dispatch($clienteId)->delay(now()->addMinutes(5));

// Síncrono (ignora a fila, roda na hora — útil em testes com QUEUE_CONNECTION=sync)
ProcessarPedidoJob::dispatchSync($pedido->id);

Dispatch de dentro de um MadComponent

use Mad\Component\MadComponent;
use Mad\Http\MadResponse;
use Mad\Ui\MadToast;

class PedidoForm extends MadComponent
{
    public MadForm $form;

    public function onSave(): MadResponse
    {
        $pedido = Pedido::create($this->form->getData());

        // Dispara em background — não bloqueia o usuário
        ProcessarPedidoJob::dispatch($pedido->id);

        return (new MadResponse())
            ->toast(MadToast::success('Pedido salvo! O processamento ocorrerá em instantes.'))
            ->closeDrawer();
    }
}

Filas múltiplas

Organize prioridades com filas nomeadas:

JobUrgente::dispatch($dados)->onQueue('critical');
EnviarEmailJob::dispatch($dados)->onQueue('emails');
GerarRelatorioJob::dispatch($dados)->onQueue('reports');
JobNormal::dispatch($dados); // fila default

Para processar com prioridade, rode workers dedicados — o primeiro nome da lista é esvaziado primeiro:

# Worker de alta prioridade (drena 'critical' antes de 'default')
php artisan queue:work --queue=critical,default

# Worker dedicado a e-mails
php artisan queue:work --queue=emails

Rodando o Worker

Desenvolvimento

php artisan queue:work
php artisan queue:work --queue=emails

cPanel / Shared hosting (via cron)

# Processa jobs por 55s e sai — cron reinicia no próximo minuto
php artisan queue:work --max-time=55

# Ou: processa apenas 1 job por invocação
php artisan queue:work --once

Produção — systemd ou Supervisor

O repositório já traz as units prontas em deploy/ (mesmo worker usado pelo MailService para entregar e-mails transacionais):

# systemd
sudo cp deploy/mad-queue-worker.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now mad-queue-worker

# Supervisor (alternativa)
sudo cp deploy/mad-queue-worker.conf /etc/supervisor/conf.d/
sudo supervisorctl reread && sudo supervisorctl update

Ambas rodam o mesmo comando:

php artisan queue:work --tries=3 --max-time=3600 --backoff=10 --sleep=3

Reinicie a cada deploy para o worker carregar o código novo — php artisan queue:restart (ou sudo systemctl restart mad-queue-worker).

Principais opções do queue:work

Opção Padrão Descrição
--queue=nome default Fila(s) a processar (vírgula define prioridade)
--once — Processa 1 job e sai
--max-time=N — Recicla o processo após N segundos (espera o job atual terminar — graceful)
--max-jobs=N — Para após processar N jobs
--sleep=N 3 Segundos de espera quando não há jobs
--tries=N 1 Tentativas por job (sobrescrito por $tries do próprio Job)
--backoff=N 0 Segundos entre tentativas quando o Job não define $backoff/backoff()
--timeout=N 60 Segundos máximos por job (mata o processo se ultrapassar)
--memory=N 128 Limite de memória (MB) antes de reciclar o worker

Importante: --max-time/--max-jobs nunca matam um job no meio — esperam o job atual terminar e só então encerram o worker.


Tratamento de falhas

Quando um job lança uma exceção não tratada, o Laravel:

  1. Decrementa as tentativas restantes;
  2. Se ainda há tentativas → reagenda com o backoff configurado;
  3. Se esgotou → move para failed_jobs com a stack trace completa e chama failed() no Job (se definido).
class MeuJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function handle(): void
    {
        // lógica
    }

    /** Chamado quando as tentativas se esgotam. */
    public function failed(\Throwable $e): void
    {
        Log::error('Job não entregue', ['error' => $e->getMessage()]);
    }
}

Gerenciando jobs falhados

# Listar jobs falhados
php artisan queue:failed

# Re-tentar um job específico (uuid)
php artisan queue:retry <uuid>

# Re-tentar todos
php artisan queue:retry all

# Esquecer (apagar) um job falhado específico
php artisan queue:forget <uuid>

# Apagar TODOS os jobs falhados
php artisan queue:flush

# Limpar jobs PENDENTES de uma fila (não mexe em failed_jobs)
php artisan queue:clear database --queue=emails

Tabelas do banco (conexão iam)

jobs — pendentes

Coluna Descrição
id ID do job
queue Nome da fila
payload JSON com classe serializada e dados
attempts Tentativas realizadas
reserved_at Quando foi pego por um worker
available_at Quando pode ser processado (delay)
created_at Criação

failed_jobs — falhados

Coluna Descrição
id / uuid Identificadores
connection / queue Onde rodava
payload JSON original
exception Stack trace completo
failed_at Quando falhou

Monitorando

A tela Central de Comando → Jobs (admin) mostra pendentes/falhados por fila em tempo real, sem precisar de SSH — útil para conferir se o worker está vivo em produção.

Veja também