11/08/2018, 20:55

Các bạn đã xếp hàng (hình) chưa ?

Đơn giản có nghĩa là khi bạn ra tiệm mua hàng nếu quá đông người theo văn minh của tây lông thì phải xếp hàng thằng nào vào trước mua trước rồi té, thằng nào vào sau xếp hàng sau mua sau ra sau (FIFO - First In First Out). Hàng đợi cho phép bạn trì hoãn xử lý một hoặc một số công việc ví dụ như gửi ...

Đơn giản có nghĩa là khi bạn ra tiệm mua hàng nếu quá đông người theo văn minh của tây lông thì phải xếp hàng thằng nào vào trước mua trước rồi té, thằng nào vào sau xếp hàng sau mua sau ra sau (FIFO - First In First Out). Hàng đợi cho phép bạn trì hoãn xử lý một hoặc một số công việc ví dụ như gửi email sau khi mua hàng sau 5 phút nhằm tăng tốc độ xử lý của ứng dụng.

Ở một ví dụ khác: Giả sử các bác có thằng cu tên Bi và các bác sai nó ra circle K mua hộ hộp durex về thổi, đồng thời vợ bác đòi nó đi mua dao cạo râu và anh các bác thì đang tám chuyện với William Cường chờ cu Bi mua giấy đem về. Như các bác thấy, nếu để cu Bi chạy đi mua đồ cùng 1 lúc ví dụ chạy lên Q12 mua durex sau đó về Q7 mua dao cạo râu rồi lại chạy lên Hóc Môn mua giấy vệ sinh thì các bác phải đợi sau khi đi mua xong toàn bộ cu Bi mới về nhà ở Q3 đưa cho bác, vợ bác, anh bác. Thay vì thế các bác nên lên cho nó cái list và để cho cu Bi tự kiểm tra rồi mua bao cho xong chạy về đưa cho bác, mua dao cạo râu rồi chạy về đưa vợ bác, và mua giấy về xong chạy về đưa cho anh bác. Các bác không cần phải đợi toàn bộ quá trình đi mua đồ của cu Bi mới có hàng xài.

Ở một thế giới khác, các bác có thể dùng hàng đợi để xử lý các tác vụ nặng như gửi email, xì-pem faceboob...vv...

  • Laravel 5.2
  • Amazon SQS

Đương nhiên là phi vô đọc document trên trang chủ Laravel - Queue rồi.
Demo kèm theo bài viết này sẽ một cái app nhỏ nhỏ gửi email nên các bác cũng cần nghía qua Laravel - Email

Clone hộ em cái app laravel sau đó đặt vhost của em là (http://thiendia.app) rồi config trong file .env chọn email driver = log cho lẹ đỡ đau não.

MAIL_DRIVER=log

email template ở resource/views/email/hi.blade.php

<h3>Em ạ các bác</h3>

Không dùng hàng đợi

em phang luôn trên routes.php cho lẹ nên các bác đừng chửi e code lầy. Mở hộ em routes.php ra tạo 1 cái route mới. Trước tiên em sẽ gửi email không dùng hàng đợi

Route::group(['middleware' => ['web']], function () {

    Route::get('/email',function(){
        Log::info("Send email without Queues started");
        Mail::send('email.hi', [], function ($message) {
            $message->from('me@xvideos.com', 'Huy Huynh');
            $message->to('you@thiendia.com');
        });
        Log::info("Send email without Queues finished");
    });

});

truy cập vào url : [yourdomain.xxx]/email sau đó mở laravel.log lên

[2016-03-29 03:58:52] local.INFO: Send email without Queues started  
[2016-03-29 03:58:52] local.DEBUG: Message-ID: <27af6a99bd67ef04fd7ddfcc1ada08a8@thiendia.app>
Date: Tue, 29 Mar 2016 03:58:52 +0000
From: Huy Huynh <me@xvideos.com>
To: you@thiendia.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<h1>Em ạ các bác</h1>  
[2016-03-29 03:58:52] local.INFO: Send email without Queues finished  

Tất cả các tác vụ đều chạy tuần tự. Vậy nếu như phải gửi khoảng 10k email các bác phải đợi hệ thống gửi, thay vì đó ta sẽ dùng hàng đợi.

Hàng đợi không delay

Em có tạo sẵn AWS SQS các bác google để biết thêm về SQS hộ em

config SQS tại configqueue.php

'sqs' => [
            'driver' => 'sqs',
            'key' => 'your-public-key',
            'secret' => 'your-secret-key',
            'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id',
            'queue' => 'your-queue-name',
            'region' => 'us-east-1',
        ],

.env

QUEUE_DRIVER=sqs

ở đây em xài SQS nên cần package aws sdk của amazon nên mở command line run lệnh:

composer require aws/aws-sdk-php
php artisan make:job SendEmail

mở file SendEmail.php vwaf generate ra

<?php

namespace AppJobs;

use AppJobsJob;
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldQueue;

class SendEmail extends Job implements ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        Mail::send('email.hi', [], function ($message) {
            $message->from('me@xvideos.com', 'Huy Huynh');
            $message->to('you@thiendia.com');
        });
    }
}

routes.php

Route::get('/email', function () {
        Log::info("Send email with Queues started");
        dispatch(new AppJobsSendEmail());
        Log::info("Send email with Queues finished");
    });

ở command line chạy lệnh để laravel listen message được gửi trả về từ SQS để call Jobs

php artisan queue:listen

truy cập lại vào [yourdomain.xxx]/email và vào laravel.log để xem kết quả

[2016-03-29 04:35:10] local.INFO: Send email with Queues started  
[2016-03-29 04:35:12] local.INFO: Send email with Queues finished  
[2016-03-29 04:35:15] local.DEBUG: Message-ID: <4a4db293b8d4f568272ceb8ba949d1bf@swift.generated>
Date: Tue, 29 Mar 2016 04:35:15 +0000
From: Huy Huynh <me@xvideos.com>
To: you@thiendia.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<h1>Em ạ các bác</h1>

Hành động gửi email sẽ chạy sau khi các bác đặt lệnh gửi email.
Với hàng đợi các bác có thể xử lý các tác vụ nặng mà không cần phải chờ đợi, gián đoạn trải nghiệm của người dùng trên website của các bác.

Bây giờ ta thử đặt delay của các task

hi.blade.php

<h1>Em ạ các bác - Delay {{ $delay }}</h1>

SendEmail.php

<?php

namespace AppJobs;

use AppJobsJob;
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldQueue;

class SendEmail extends Job implements ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    public $delay;

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

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        Mail::send('email.hi', ['delay' => $this->delay], function ($message) {
            $message->from('me@xvideos.com', 'Huy Huynh');
            $message->to('you@thiendia.com');
        });
    }
}

routes.php

Route::get('/email', function () {
        Log::info("Send email with Queues started");
        dispatch((new AppJobsSendEmail(120))->delay(120));
        dispatch((new AppJobsSendEmail(30))->delay(30));
        dispatch((new AppJobsSendEmail(60))->delay(60));
        Log::info("Send email with Queues finished");
    });

Chạy lại một lần nữa và xem log

[2016-03-29 04:45:01] local.INFO: Send email with Queues started  
[2016-03-29 04:45:03] local.INFO: Send email with Queues finished  
[2016-03-29 04:45:36] local.DEBUG: Message-ID: <84a4f7e5238f5d05ed83fa1b60e2a67c@swift.generated>
Date: Tue, 29 Mar 2016 04:45:36 +0000
From: Huy Huynh <me@xvideos.com>
To: you@thiendia.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<h1>Em ạ các bác - Delay 30</h1>  
[2016-03-29 04:46:16] local.DEBUG: Message-ID: <1ddba85701af5c85d6c44cff2e80b47c@swift.generated>
Date: Tue, 29 Mar 2016 04:46:16 +0000
From: Huy Huynh <me@xvideos.com>
To: you@thiendia.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<h1>Em ạ các bác - Delay 60</h1>  
[2016-03-29 04:47:06] local.DEBUG: Message-ID: <2ae01f89d068003a94c5f3193b3715c5@swift.generated>
Date: Tue, 29 Mar 2016 04:47:06 +0000
From: Huy Huynh <me@xvideos.com>
To: you@thiendia.com
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<h1>Em ạ các bác - Delay 120</h1>

Theo như sắp xếp của chúng ta ở file routes task delay 120 > 30 > 60 nhưng khi xem log task nào có delay thấp nhất sẽ chạy trước tiên.

Qua bài viết này em giới thiệu sơ bộ về hàng đợi, có thể bài viết của em hơi khó hiểu và có thiếu sót ở 1 vài chỗ mong các bác bỏ qua, hy vọng nó sẽ giúp các bác trong dự án thực tế. Em đã từng áp dụng hàng đợi trên nhiều dự án khác nhau và kết quả mang lại làm em rất hài lòng. Trong phần tiếp theo em sẽ giới thiệu về AWS SQS để bổ sung thiếu sót cho bài viết này.
Ngoài ra các bác không thích dùng SQS có thể tham khảo thêm các phương thức khác mà Laravel hỗ trợ cho hàng đợi. Đối với riêng em em thấy AWS awesome vl tuy giá mắc vãi :v

0