Blog EspecializaTi
Carlos Ferreira Por: Carlos Ferreira Comentar

Queues no Laravel (Filas)

Queues no Laravel

Imagine uma aplicação recebendo uma demanda muito grande de solicitações simultaneamente ao mesmo tempo, e mais do que isso, o processo solicitado é algo pesado, ou seja, tem um tempo de processamento demorado, e o time de resposta é demorado, como por exemplo um envio de e-mail. Imaginou?

Se sua aplicação precisar processar algo pesado (que o tempo de resposta é grande) o ideal é liberar o usuário, ou seja, não travar a aplicação, e executar essa tarefa durante o tempo ocioso do servidor. Além de melhorar a usabilidade da aplicação, por não travar no momento de fazer aquela determinada requisição, isso ainda ajuda a economizar “recursos” do servidor, e trabalhar de forma mais inteligente sem sobrecarregar com múltiplos processos simultâneos.

 

Ah, mas como fazer isso?

Filas (Queues)! O Laravel tem recursos nativos para trabalhar com processos usando filas. Esse recurso permite o sistema executar tarefas de forma sequencial, sem sobrecarregar a aplicação com múltiplos processos simultâneos.
Quando adiciona uma tarefa na fila (queue) define uma sequência exata para o processamento das tarefas (que pode ser enviar um e-mail, registrar log, escrever em um arquivo e etc), e isso garante que o processador não fique executando múltiplas tarefas paralelas, e com isso resulta em um melhor aproveitamento dos recursos do server.

 

Queues na Prática

O arquivo de configuração de filas no Laravel fica em config/queue.php

Os formatos de drivers suportados são: database, Beanstalkd, Amazon SQS, Redis, sync (processamento imediato), e null.

 

Queues database:

Nesse exemplo vamos trabalhar com o driver database, precisamos criar uma tabela, que vai conter todos as tarefas que devem ser executadas (processadas), e a medida que são processadas são descartadas do banco de dados.

Para criar a estrutura da tabela (arquivo de migration) deve rodar o comando:

php artisan queue:table

Esse comando vai criar o arquivo de migration: database/migrations/timestamps_aqui_create_jobs_table.php que contém a estrutura da tabela jobs, que é a tabela que contém a estrutura das queues que precisarão ser processadas.

Após criar a migration o próximo passo é obviamente criar a tabela, a partir da migration, para isso rode o comando:

php artisan migrate

Agora que decidimos que o formato de processamento das filas será por database, precisa alterar as configurações setando essa opção. No arquivo config/queue.php fica essas configurações, precisamos alterar o valor de “default” para definir essa configuração, por padrão (default) está definido como sync, neste caso precisamos alterar para database, observe que está pegando essa informação do arquivo .env:

'default' => env('QUEUE_DRIVER', 'sync'),

Então vamos alterar no arquivo .env o QUEUE_DRIVER para database:

QUEUE_DRIVER=database

Quando definimos nosso QUEUE_DRIVER para database, vai pegar as configurações do arquivo config/queue.php em connections > database:

'connections' => [
    // [...]

    'database' => [
        'driver' => 'database',
        'table' => 'jobs',
        'queue' => 'default',
        'retry_after' => 90,
    ],

    // [...]
],

 

Jobs:

Existem N formas de executar algum processo com Queues (filas), uma delas é criar uma classe especifica para fazer o processo de filas.

Jobs são classes que ficam armazenadas em app/Jobs/ e são processadas pelo sistema de Queues do Laravel.
Para criar uma nova classe de JOB rode este comando:

php artisan make:job SendWelcomeEmail

Essa classe que foi gerada, implementa a interface Illuminate\Contracts\Queue\ShouldQueue, para que o processamento seja realizado usando queue.

 

Enviando e-mail de boas vindas:

Nesse exemplo vamos enviar um e-mail de boas vindas ao usuário que acabou de se cadastrar no sistema, veja como fica a implementação da nossa classe de JOB SendWelcomeEmail:

namespace App\Jobs;

use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeEmail;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

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

    private $user;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Execute the job.
     *
     * @param  User  $user
     * @return void
     */
    public function handle()
    {
        // Send email welcome user
        Mail::to($this->user->email)
                ->send(new WelcomeEmail($this->user));
    }
}

O método construtor em nossa classe espera um objeto com os dados do usuário que acabou de ser cadastrado. Já no método handle() é onde fica o processamento.

O próximo passo é criar a classe para o envio de e-mail WelcomeEmail:

php artisan make:mail WelcomeEmail

Nessa classe vamos passar o objeto do usuário que acabou de ser cadastrado:

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class WelcomeEmail extends Mailable
{
    use Queueable, SerializesModels;

    private $user;

    /**
     * Create a new message instance.
     *
     * @param  User  $user
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->markdown('emails.created.welcome')
                    ->subject('Boas Vindas!!!')
                    ->with([
                        'user' => $this->user,
                    ]);
    }
}

Observe que neste exemplo estamos usando uma view com Markdown, então precisamos criar a view com a sua estrutura (resources/views/emails/created/welcome.blade.php):

@component('mail::message')
# Boas Vindas

Seja muito bem vindo a nossa plataforma 🙂

@component('mail::button', ['url' => config('app.url')])
Acessar o Site
@endcomponent

Obrigado,
{{ config('app.name') }}
@endcomponent
OBS: Para configurações de e-mail em ambiente de desenvolvimento, sugiro o Mailtrap.io (leia sobre!)

O JOB está pronto, a classe de envio de e-mails também, agora nos resta disparar o JOB.

 

Dispatching Jobs:

Para disparar (rodar/processar) o JOB a implementação é a seguinte:

NameJob::dispatch($object);

Nesse exemplo só vamos disparar o JOB para rodar a fila (queue) quando um novo usuário se registrar, para conseguir fazer isso precisamos trabalhar com os Observers do Laravel, para monitorar um novo cadastro e disparar o nosso JOB que vai enviar o e-mail de boas vindas.

Vamos criar um Observer que vai monitorar o evento de created (usuário cadastrado), para isso rode este comando:

php artisan make:observer UserObserver --model=User

Criou um novo arquivo de classe em em app/Observers/UserObserver.php

Um Observer é possível monitorar alguns eventos do usuário, como created (usuário registrado), updated (usuário editado), deleted (usuário deletado). Neste caso o que nos interessa é o created, veja como fica a implementação:

namespace App\Observers;

use App\Jobs\SendWelcomeEmail;
use App\Models\User;

class UserObserver
{
    /**
     * Handle to the user "created" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function created(User $user)
    {
        // Dispatching Job SendWelcomeEmail
        SendWelcomeEmail::dispatch($user);
    }

    // [...]
}

O próximo passo é registrar o Observer no Provider AppServiceProvider (app/Providers/AppServiceProvider.php):

namespace App\Providers;

use App\Models\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
    }

    // [...]
}

 

Rodar Queues no Laravel:

Se registrar um novo usuário nada vai acontecer, mas por que? Porque falta executar os jobs (as queues que precisam ser executadas). Se observar na tabela jobs (que foi criada mais acima) ela consta esse registro, agora falta processar.

Para processar as filas (queues) rode este comando:

php artisan queue:work

Pouco tempo depois os e-mails de boas vindas começam a chegar aos respectivos usuários.

OBS: Muitas camadas dentro do Laravel permitem trabalhar com Queues diretamente nelas, como E-mails, Eventos, Notifications e etc. Para esses casos basta a classe implementar a interface Illuminate\Contracts\Queue\ShouldQueue

 

Queues em produção:

Em produção o serviço mais recomendado é o Supervisor (saiba mais).

Esse tema de Queues em produção pode (talvez) ser um tema para um próximo tutorial.

 

Vamos ficando por aqui, espero que tenha gostado, e já sabe, qualquer dúvida só deixar aquele comentário. 🙂

 

Abraços []’s

 

Carlos Ferreira

Sobre o Autor:

Carlos Ferreira

Carlos Ferreira é Analista de Sistemas Experiente, Empreendedor, Fundador da empresa EspecializaTi. Certificações: Comptia Linux +, LPI, Novell Certification.

Todos os direitos reservados © 2018 - EspecializaTi. É proibida a reprodução total ou parcial deste conteúdo.