Queues e Jobs no Laravel
1. Introdução às Queues no Laravel
Queues (filas) são um dos recursos mais poderosos do Laravel para processamento assíncrono de tarefas. Em vez de executar operações demoradas — como envio de e-mails, geração de relatórios ou processamento de imagens — diretamente na requisição HTTP, você pode adiá-las para serem processadas em segundo plano. Isso libera o servidor web rapidamente, melhorando a experiência do usuário.
Em aplicações PHP tradicionais, tudo é síncrono. O usuário espera até que o servidor termine de processar e devolva a resposta. Com filas, você coloca a tarefa em uma fila e retorna imediatamente ao usuário. Um worker separado processa a tarefa assincronamente.
O Laravel suporta diversos drivers de fila: Redis (rápido, recomendado para produção), Database (simples, ótimo para desenvolvimento), Amazon SQS (serviço gerenciado da AWS), Beanstalkd e Synchronous (para testes). A escolha depende da sua infraestrutura e necessidades de escalabilidade.
2. Configuração e Preparação do Ambiente
A configuração principal fica em config/queue.php. Vamos usar o driver Database para este exemplo prático, pois não requer dependências externas.
// config/queue.php
'default' => env('QUEUE_CONNECTION', 'database'),
'connections' => [
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
'after_commit' => true,
],
// ... outros drivers
],
Crie a tabela de jobs com o comando Artisan:
php artisan queue:table
php artisan migrate
Isso gera uma migration que cria a tabela jobs, com colunas para payload, tentativas, reserva e timestamps. A variável de ambiente QUEUE_CONNECTION no .env define qual conexão usar.
3. Criando e Despachando Jobs
Jobs são classes que encapsulam a lógica a ser executada na fila. Crie um job com:
php artisan make:job SendWelcomeEmail
A classe gerada contém um método handle() e propriedades públicas para dados injetados:
<?php
namespace App\Jobs;
use App\Models\User;
use App\Mail\WelcomeMail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Mail;
class SendWelcomeEmail implements ShouldQueue
{
use Queueable;
public function __construct(
public User $user
) {}
public function handle(): void
{
Mail::to($this->user->email)->send(new WelcomeMail($this->user));
}
}
Despache o job de várias formas:
// Despacho padrão (vai para a fila)
SendWelcomeEmail::dispatch($user);
// Execução síncrona (útil para testes)
SendWelcomeEmail::dispatchSync($user);
// Executar após enviar a resposta HTTP
SendWelcomeEmail::dispatchAfterResponse($user);
// Com atraso de 10 minutos
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));
// Em uma fila específica com prioridade
SendWelcomeEmail::dispatch($user)->onQueue('high');
4. Processamento e Gerenciamento de Filas
Para processar os jobs, execute o worker:
php artisan queue:work
Opções importantes do worker:
# Processar apenas a fila 'high'
php artisan queue:work --queue=high,default
# Máximo de 3 tentativas por job
php artisan queue:work --tries=3
# Timeout de 60 segundos para cada job
php artisan queue:work --timeout=60
# Dormir 3 segundos entre verificações
php artisan queue:work --sleep=3
Para produção, use o Supervisor para manter o worker rodando continuamente. Exemplo de configuração do Supervisor:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/var/log/supervisor/worker.log
Para ver jobs falhos:
php artisan queue:failed
php artisan queue:retry all
php artisan queue:flush
5. Tratamento de Falhas e Retentativas
Configure tentativas máximas na classe do job:
class SendWelcomeEmail implements ShouldQueue
{
public $tries = 5; // ou use maxAttempts
public function failed(Throwable $exception): void
{
// Logar o erro ou notificar equipe
Log::error('Falha ao enviar e-mail', [
'user' => $this->user->id,
'error' => $exception->getMessage()
]);
}
}
Para jobs com timeout personalizado:
public $timeout = 120; // segundos
Middlewares de fila permitem lógica antes/depois da execução:
// App/Jobs/Middleware/RateLimited.php
public function handle(Job $job, $next)
{
$this->limiter->throttle('email-sending', 10, function () use ($job, $next) {
$next($job);
});
}
6. Recursos Avançados de Jobs
Job Chaining (encadeamento): execute jobs em sequência, parando se um falhar:
Bus::chain([
new ProcessPodcast($podcast),
new OptimizePodcast($podcast),
new ReleasePodcast($podcast),
])->dispatch();
Jobs únicos (ShouldBeUnique): evita duplicatas na fila:
class SendWelcomeEmail implements ShouldBeUnique
{
public function uniqueId(): string
{
return $this->user->id;
}
public $uniqueFor = 3600; // segundos
}
Rate limiting em jobs:
public function middleware(): array
{
return [
new RateLimited('email-sending')
];
}
Batch Jobs (lotes): processe grupos de jobs com progresso:
$batch = Bus::batch([
new ProcessUser($user1),
new ProcessUser($user2),
new ProcessUser($user3),
])->then(function (Batch $batch) {
// Todos os jobs completaram com sucesso
})->catch(function (Batch $batch, Throwable $e) {
// Primeiro job falhou
})->finally(function (Batch $batch) {
// Lote finalizou (sucesso ou falha)
})->dispatch();
// Rastrear progresso
$batch->progress(); // 0 a 100
7. Eventos e Notificações Relacionados a Filas
O Laravel dispara eventos durante o ciclo de vida dos jobs:
// App/Providers/AppServiceProvider.php
use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobFailed;
public function boot(): void
{
Queue::before(function (JobProcessing $event) {
Log::info('Processando job: ' . $event->job->getName());
});
Queue::after(function (JobProcessed $event) {
// Job processado com sucesso
});
Queue::failing(function (JobFailed $event) {
Log::error('Job falhou: ' . $event->job->getName(), [
'exception' => $event->exception
]);
});
}
Notificações em fila são automáticas quando a notificação implementa ShouldQueue:
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
public function via($notifiable): array
{
return ['mail'];
}
public function toMail($notifiable): MailMessage
{
return (new MailMessage)
->line('Sua fatura foi paga!');
}
}
// Despachar notificação em background
$user->notify(new InvoicePaid($invoice));
Exemplo prático: e-mail em background com fila:
public function register(Request $request): RedirectResponse
{
$user = User::create($request->validated());
// Enfileira o e-mail de boas-vindas
SendWelcomeEmail::dispatch($user);
return redirect()->route('dashboard')
->with('success', 'Conta criada! Você receberá um e-mail em breve.');
}
8. Boas Práticas e Performance
Quando usar filas:
- Envio de e-mails e notificações
- Processamento de imagens/vídeos
- Geração de relatórios e PDFs
- Integrações com APIs externas
- Qualquer tarefa que demore mais de 500ms
Armadilhas a evitar:
- Evite serializar objetos Eloquent com relacionamentos carregados (use apenas o ID)
- Use mutex para operações concorrentes que alteram o mesmo recurso
- Cuidado com deadlocks em transações de banco de dados dentro de jobs
Monitoramento com Horizon (Redis):
composer require laravel/horizon
php artisan horizon:install
php artisan horizon
Horizon fornece dashboard em tempo real, métricas de throughput e balanceamento automático de workers.
Testando jobs com Pest:
test('send welcome email job', function () {
Queue::fake();
$user = User::factory()->create();
SendWelcomeEmail::dispatch($user);
Queue::assertPushed(SendWelcomeEmail::class, function ($job) use ($user) {
return $job->user->id === $user->id;
});
// Processar job manualmente
(new SendWelcomeEmail($user))->handle();
Mail::assertSent(WelcomeMail::class);
});
Referências
- Documentação Oficial: Queues no Laravel — Guia completo sobre filas, jobs, workers e configuração.
- Laravel Horizon: Monitoramento de Filas — Dashboard e gerenciamento avançado de filas com Redis.
- Laravel News: Understanding Queues and Jobs — Artigo técnico com exemplos práticos de jobs e workers.
- Laravel Daily: Queue Tutorial with Examples — Tutorial passo a passo com Database e Redis drivers.
- Spatie: Laravel Queueable Actions — Pacote para criar actions que podem ser enfileiradas com boas práticas.