Laravel Jobs, Queues e Events na Prática na Prática Já leu

Entendendo Jobs, Queues e Events no Laravel Jobs, queues e events são pilares para construir aplicações Laravel escaláveis e responsivas. Um Job é uma unidade de trabalho que pode ser executada de forma assíncrona, fora do ciclo de requisição HTTP. Queues (filas) armazenam e processam esses jobs em background, enquanto Events permitem que você despache ações que múltiplos listeners podem responder. A combinação desses três conceitos resolve problemas reais: enviar 10 mil e-mails sem travar a aplicação, processar uploads pesados e manter o código desacoplado e testável. Nesta aula, você aprenderá não apenas como implementar, mas quando usar cada ferramenta. Vamos trabalhar com exemplos práticos que funcionam imediatamente em seu projeto Laravel. Jobs e Queues na Prática Criando e Despachando um Job Um job é criado com o comando . Imagine que você precisa processar um pedido de compra que envolve validações externas, envio de e-mail e atualização de inventário. Essa tarefa não deve bloquear a resposta ao cliente. O

Entendendo Jobs, Queues e Events no Laravel

Jobs, queues e events são pilares para construir aplicações Laravel escaláveis e responsivas. Um Job é uma unidade de trabalho que pode ser executada de forma assíncrona, fora do ciclo de requisição HTTP. Queues (filas) armazenam e processam esses jobs em background, enquanto Events permitem que você despache ações que múltiplos listeners podem responder. A combinação desses três conceitos resolve problemas reais: enviar 10 mil e-mails sem travar a aplicação, processar uploads pesados e manter o código desacoplado e testável.

Nesta aula, você aprenderá não apenas como implementar, mas quando usar cada ferramenta. Vamos trabalhar com exemplos práticos que funcionam imediatamente em seu projeto Laravel.

Jobs e Queues na Prática

Criando e Despachando um Job

Um job é criado com o comando make:job. Imagine que você precisa processar um pedido de compra que envolve validações externas, envio de e-mail e atualização de inventário. Essa tarefa não deve bloquear a resposta ao cliente.

php artisan make:job ProcessPurchaseOrder

O job gerado fica em app/Jobs/ProcessPurchaseOrder.php:

<?php

namespace App\Jobs;

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

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

    public function __construct(
        public Order $order
    ) {}

    public function handle()
    {
        // Validar com API externa
        $response = httpClient()->get('https://api.validate.com/orders', [
            'order_id' => $this->order->id
        ]);

        if ($response->successful()) {
            $this->order->update(['status' => 'validated']);
            \Mail::to($this->order->customer_email)->send(new OrderConfirmed($this->order));
        }
    }

    public function failed(\Throwable $exception)
    {
        \Log::error('Job failed: ' . $exception->getMessage());
        $this->order->update(['status' => 'failed']);
    }
}

Para despachar o job de forma assíncrona:

// No controller
public function store(Request $request)
{
    $order = Order::create($request->validated());

    ProcessPurchaseOrder::dispatch($order);

    return response()->json(['message' => 'Pedido recebido!'], 202);
}

Configurando a Queue

Por padrão, Laravel usa o driver sync que executa jobs imediatamente. Para verdadeiro processamento em background, configure o driver database ou redis em .env:

QUEUE_CONNECTION=database

Crie a tabela de jobs com: php artisan queue:table e php artisan migrate.

Inicie um worker para processar jobs:

php artisan queue:work

Este comando fica em loop, aguardando novos jobs na fila. Em produção, use supervisord ou similares para manter o worker ativo.

Events e Listeners para Desacoplamento

O Poder da Arquitetura Event-Driven

Events desacoplam sua lógica. Em vez de colocar tudo no controller, você dispara um evento e múltiplos listeners reagem. Imagine: quando um usuário se registra, você precisa enviar e-mail de boas-vindas, registrar no CRM, e atualizar analytics. Sem events, seu controller vira um caos. Com events, cada responsabilidade fica isolada.

php artisan make:event UserRegistered
php artisan make:listener SendWelcomeEmail --event=UserRegistered
php artisan make:listener LogToAnalytics --event=UserRegistered

O event em app/Events/UserRegistered.php:

<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public User $user) {}
}

Listener que envia e-mail em background:

<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Mail\WelcomeEmail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Mail;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user->email)->send(new WelcomeEmail($event->user));
    }
}

Registre listeners em app/Providers/EventServiceProvider.php:

protected $listen = [
    UserRegistered::class => [
        SendWelcomeEmail::class,
        LogToAnalytics::class,
    ],
];

Dispache o event do seu controller:

public function register(Request $request)
{
    $user = User::create($request->validated());
    UserRegistered::dispatch($user);

    return response()->json(['user' => $user], 201);
}

Listeners com Queue vs Síncronos

Por padrão, listeners executam no mesmo processo. Implemente ShouldQueue no listener para executá-lo em background:

class LogToAnalytics implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // Será enfileirado automaticamente
        Analytics::track('user_registered', ['user_id' => $event->user->id]);
    }
}

Integrando Jobs, Queues e Events

Caso de Uso Real: Processamento de Relatório

Combine os três conceitos para um cenário realista. Um usuário solicita um relatório PDF grande:

// Event disparado quando relatório é solicitado
php artisan make:event ReportRequested
class ReportRequested
{
    public function __construct(public Report $report, public User $user) {}
}

Listener que despacha o job:

class GenerateReportPdf implements ShouldQueue
{
    public function handle(ReportRequested $event): void
    {
        GenerateReport::dispatch($event->report, $event->user);
    }
}

Job que processa pesadamente:

class GenerateReport implements ShouldQueue
{
    public $timeout = 300; // 5 minutos

    public function __construct(
        protected Report $report,
        protected User $user
    ) {}

    public function handle()
    {
        $data = $this->report->getComplexData();
        $pdf = \PDF::loadView('reports.template', $data);

        Storage::disk('s3')->put(
            "reports/{$this->report->id}.pdf",
            $pdf->output()
        );

        ReportGenerated::dispatch($this->report, $this->user);
    }

    public function failed(\Throwable $exception)
    {
        \Notification::send($this->user, new ReportFailedNotification());
    }
}

Listener final que notifica o usuário:

class NotifyReportReady
{
    public function handle(ReportGenerated $event): void
    {
        \Notification::send(
            $event->user,
            new ReportReadyNotification($event->report)
        );
    }
}

No controller, tudo é simples:

public function requestReport(Request $request)
{
    $report = Report::create($request->validated());
    ReportRequested::dispatch($report, auth()->user());

    return response()->json(['message' => 'Relatório em processamento']);
}

Conclusão

Os três pilares — Jobs para executar trabalho assíncrono, Queues para gerenciar fila de processamento e Events para desacoplar lógica — transformam aplicações Laravel em sistemas responsivos e escaláveis. Use jobs quando há trabalho pesado que não precisa bloquear o usuário. Implemente events quando múltiplos componentes precisam reagir ao mesmo acontecimento. Configure queues com Redis em produção para performance máxima. A arquitetura correta desde o início economiza refatorações futuras.

Referências


Artigos relacionados