+7

Laravel: Tìm hiểu về queues. (Phần 1)

Introduction


Laravel queues cung cấp một API thống nhất trên nhiều loại queue backend khác nhau, như Beanstalk, Amazon SQS, Redis, hoặc ngay cả cở sở dữ liệu quan hệ. Queues cho phép bạn hoãn lại tiến trình của task, như gửi mail, cho đến một thời gian nào đó. Việc hoãn những task mất nhiều thời gian này sẽ làm tăng tốc độ cho ứng dụng web của bạn.

Cấu hình queue được lưu tại thư mục config/queue.php. Trong file này bạn sẽ tìm kết nối với mỗi queue drivers mà bạn thêm vào framework, nó bao gồm Beanstalkd, Amazon SQS, Redis, và synchronous driver sẽ thực hiện công việc ngay lập tức (cho local sử dụng). Một null queue driver cũng được include và đơn giản là thực hiện loại bỏ queued jobs.


Connections Vs. Queues

Trước khi bắt đầu với Laravel queues, điều quan trọng là bạn cần hiểu sự khác biệt giữa "connections" và "queues". Trong file cấu hình config/queue.php, có một tùy chọn connections. Tùy chọn này sẽ định nghĩa một connection cụ thể vào một backend service như Amazon SQS, Beanstalk, hoặc Redis. Tuy nhiên, bất kỳ queue connection có thể có nhiều "queues" mà có thể được coi như các stacks khác nhau hoặc các queued jobs.

Chú ý rằng mỗi ví dụ cấu hình connection trong file cấu hình queue chứa một thuộc tính queue. Đây là queue mặc định mà các job sẽ được gửi tới khi chúng được gửi tới một connection. Nói cách khác, nếu bạn gửi một job mà không xác định rõ queue nào cần gửi đến, job sẽ được đặt trên queue được đinh nghĩa trong queue attribute của cấu hình connection:

// This job is sent to the default queue...
dispatch(new Job);

// This job is sent to the "emails" queue...
dispatch((new Job)->onQueue('emails'));

Một số ứng dụng có thể không cần phải push các job vào multiple queue, thay vì prefer 1 simple queue. Tuy nhiên, việc đẩy (push) job cho nhiều queue có thể đặc biệt hữu ích cho các ứng dụng muốn sắp xếp thứ tự ưu tiên hoặc phân công công việc được xử lý, vì Laravel queue worker cho phép bạn chỉ định các queue cần xử lý theo độ ưu tiên. Ví dụ, bạn muốn push các công việc vào high queue, bạn có thể chạy 1 worker có độ ưu tiên cao hơn:

php artisan queue:work --queue=high,default

Driver Prerequisites


Database

Để sử dụng database queue driver, bạn sẽ cần một database để giữ các job. Để generate một migration tạo ra table này, chạy lệnh Artisan queue:table. Khi migration được khởi tạo, bạn có thể migrate database của bạn bằng cách sử dụng câu lệnh migrate.

php artisan queue:table

php artisan migrate

Redis

Để sử dụng redis queue driver, bạn nên cấu hình một kết nối Redis database trong file cấu hình config/database.php. Nếu kết nối Redis queue của bạn sử dụng một Redis Cluster, tên queue của bạn phải chứa một key hash tag. Điều này là cần thiết để đảm bảo tất cả các Redis key cho một queue nhất định được đặt vào cùng một vị trí hash giống nhau.

'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => '{default}',
    'retry_after' => 90,
],

Other Driver Prerequisites

Các dependence sau đây là cần thiết cho các listed queue driver.

  • Amazon SQS: aws/aws-sdk-php ~3.0
  • Beanstalkd: pda/pheanstalk ~3.0
  • Redis: predis/predis ~1.0

Creating Jobs


Generating Job Classes

Theo mặc định, tất cả các job có thể xếp hàng cho ứng dụng của bạn được lưu trữ trong thư mục app/Jobs Nếu thư mục app\Jobs không tồn tại, nó sẽ được tạo ra khi bạn chạy lệnh Artisan make:job. Bạn có thể tạo ra 1 queued job mới sử dụng Artisan CLI

php artisan make:job SendReminderEmail

Class được tạo sẽ implement interface Illuminate\Contracts\Queue\ShouldQueue, chỉ ra cho Laravel rằng job cần được đẩy lên hàng đợi để chạy không đồng bộ

Class Structure

Các class Job rất đơn giản, thường chỉ chứa một phương thức handle được gọi khi job được xử lý bơi queue. Để bắt đầu, hãy xem một ví dụ về class job. trong ví dụ này, ta sẽ giả vờ chúng ta quản lý 1 dịch vụ xuất bản podcast và cần xử lý file podcast trước khi chúng được xuất bản:

<?php

namespace App\Jobs;

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

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

    protected $podcast;

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

    /**
     * Execute the job.
     *
     * @param  AudioProcessor  $processor
     * @return void
     */
    public function handle(AudioProcessor $processor)
    {
        // Process uploaded podcast...
    }
}

Trong ví dụ này, lưu ý rằng chúng ta đã có thể pass qua Eloquent model trực tiếp đến construct của queue job. Vì SerializesModels trait mà job được sử dụng, các Eloquent model sẽ ddwwocj sắp xếp theo thứ tự và không tuần tự một cách hợp lý khi job đang được xử lý. Nếu queue job của bạn chấp nhận một Eloquent model trong constructor của nó, chỉ có định danh cho model sẽ được tuần tự hóa vào queue. Khi queue job được xử lý, queue system sẽ tự động lấy lại model instance từ database. Tất cả đều minh bach cho ứng dụng của bạn và ngăn ngừa các vấn đề có thể phát sinh từ việc serializing tất cả các instance của Eloquent model.

Phương thức handle được gọi khi job ddwwocj xử lý bởi queue. Lưu ý rằng chúng ta có thể type-hint dependence trên phương thước handle của job. Laravel service container tự động inject các dependence này.


Dispatching Jobs


Một khi bạn đã viết class job của bạn, bạn có thể gửi nó đi bằng cách sử dụng dispatch helper. Một đối số duy nhất bạn cần pass cho dispatch helper là một instance của job:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        dispatch(new ProcessPodcast($podcast));
    }
}

Delayed Dispatching


Nếu bạn muốn trì hoãn việc thực hiện job đã được xếp hàng, bạn có thể sử dụng phương thức delay trên instance job của bạn. Phương thức delay được cung cấp bởi Illuminate\Bus\Queueable trait, được include mặc định trên tất cả các class job được tạo ra. Ví dụ, chúng ta hãy chỉ định một job không có sẵn để xử lý cho đến 10 phút sau khi nó đc dispatch:

<?php

namespace App\Http\Controllers;

use Carbon\Carbon;
use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        $job = (new ProcessPodcast($podcast))
                    ->delay(Carbon::now()->addMinutes(10));

        dispatch($job);
    }
}

Customizing The Queue & Connection


Dispatching To A Particular Queue

Bằng cách push các job đến các queue khác nhau, bạn có thể phân loại job được xếp hàng và thâm chí ưu tiên số worker bạn chỉ định cho các queue khác nhau. Lưu ý rằng điều này không push job đến các queue "connections" khác nhau như được định nghĩa bởi file cấu hình queue của bạn, nhưng chỉ các queue chỉ định trong một single connection. Để xác định queue, sử dụng phương thức onQueue trên instance job:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        $job = (new ProcessPodcast($podcast))->onQueue('processing');

        dispatch($job);
    }
}

Dispatching To A Particular Connection

Nếu bạn đang làm việc với multiple queue connection, bạn có thể chỉ định connection nào để push một job. Để chỉ định connection, sử dụng phương thức onConnection trên instance job:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * Store a new podcast.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Create podcast...

        $job = (new ProcessPodcast($podcast))->onConnection('sqs');

        dispatch($job);
    }
}

Dĩ nhiên, bạn có thể nối các phương thức onConnectiononQueue để chỉ đinh connection và queue cho một job.

$job = (new ProcessPodcast($podcast))
                ->onConnection('sqs')
                ->onQueue('processing');

Specifying Max Job Attempts / Timeout Values


Max Attempts

Một cách tiếp cận để chỉ định số lần tối đa của job có thể được thực hiện là thông qua --tries trên câu lệnh Artisan:

php artisan queue:work --tries=3

Tuy nhiên, bạn có thể thực hiện một cách tiếp cận chi tiết hơn bằng cách xác định số lần tối đa trên job class. Nếu số lần tối đa của attempt được chỉ đinh trên job, nó sẽ được ưu tiên hơn giá trị được cung cấp bởi dòng lệnh:

<?php

namespace App\Jobs;

class ProcessPodcast implements ShouldQueue
{
    /**
     * The number of times the job may be attempted.
     *
     * @var int
     */
    public $tries = 5;
}

Timeout

Tương tự như vậy, số giây tối đa mà các job được chạy có thể chỉ định bằng cách sử dụng --timeout trên dòng lệnh Artisan:

php artisan queue:work --timeout=30

Tuy nhiên, bạn cũng có thể chỉ định số giây tối đa mà 1 job được chạy trên class job. Nếu thời gian được chỉ định cho job, nó sẽ được ưu tiên hơn khi chỉ định trên dòng lệnh:

<?php

namespace App\Jobs;

class ProcessPodcast implements ShouldQueue
{
    /**
     * The number of seconds the job can run before timing out.
     *
     * @var int
     */
    public $timeout = 120;
}

Tài liệu: Tại trang chủ của Laravel


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí