+1

Task Scheduling with Cron Job in Laravel 5.8

I. Giới thiệu

Trước đây, lập trình viên phải tạo ra các dòng cron cho mỗi task cần được schedule. Tuy nhiên, việc này khá đau đầu. Việc đặt lịch cho task không nằm trong source control, và bạn phải SSH vào trong server và thêm vào các nội dung cron.

Task Scheduling của Laravel cho phép bạn define các lệnh đặt lịch một cách liền mạch và rõ ràng, và bạn chỉ cần thực hiện thêm đúng một dòng Cron cần thiết vào trong server. Việc đặt lịch task được định nghĩa bên trong file app/Console/Kernel.php và trong hàm schedule. Để giúp bạn bắt đầu, một ví đụ đơn giản được ghi sẵn bên trong hàm đó. Bạn tuỳ ý thêm bao nhiêu task tuỳ thích vào trong đối tượng.

Khởi động Scheduler

Khi dùng scheduler, bạn chỉ cần thêm dòng Cron duy nhất mà bạn cần thêm vào trong server của bạn

* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1

Định nghĩa Schedules

Bạn có thể định nghĩa các task bên trong hàm schedule của class App\Console\Kernel.

Để bắt đầu, hãy cùng nhìn vào ví dụ sau về lên lịch cho một task. Trong ví dụ này, chúng ta sẽ lên lịch cho một Closure được gọi mỗi ngày vào lúc nửa đêm. Bên trong Closure chúng ta sẽ thực thi một database query để xoá một bảng:

<?php

namespace App\Console;

use Illuminate\Support\Facades\DB;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->call(function () {
            DB::table('recent_users')->delete();
        })->daily();
    }
}
Scheduling Queued Jobs

Phương thức job có thể được sử dụng để đặt lịch một queued job

$schedule->job(new Heartbeat)->everyFiveMinutes();

// Dispatch the job to the "heartbeats" queue...
$schedule->job(new Heartbeat, 'heartbeats')->everyFiveMinutes();

Tùy chọn phương thức Schedule

Trong bước này, chúng ta cần xác định các lệnh của mình trong fileKernel.php theo thời gian.

Phương thức Miêu tả
->cron('* * * * * *'); Chạy task với lịch Cron tuỳ chọn
->everyMinute(); Chạy từng phút
->everyFiveMinutes(); Cứ 5 phút chạy một lần
->everyTenMinutes(); Cứ 10 phút chạy một lần
->everyThirtyMinutes(); Cứ 30 phút chạy một lần
->hourly(); Cứ mỗi tiếng chạy một lần
->hourlyAt(17); Chạy ở phút thứ 17 của mỗi giờ
->daily(); Chạy hàng ngày lúc nửa đêm
->dailyAt('13:00'); Chạy hàng ngày lúc 13:00
->twiceDaily(1, 13); Chạy hàng ngày tại 1:00 & 13:00
->weekly(); Chạy hàng tuần
->weeklyOn(1, '8:00'); Chạy vào 8:00 Thứ 2 mỗi tuần
->monthly(); Chạy hàng tháng
->monthlyOn(4, '15:00'); Chạy vào ngày mùng 4 hàng tháng lúc 15:00
->quarterly(); Cứ mỗi quý chạy một lần
->yearly(); Mỗi năm chạy một lần
->timezone('America/New_York'); Thiết lập timezone

Các hàm này có thể phối hợp nhau để tạo ràng buộc chạy các kiểu lịch phức tạp hơn. Ví dụ như chạy một câu lệnh hàng tuần vào thứ hai:

// Run once per week on Monday at 1 PM...
$schedule->call(function () {
    //
})->weekly()->mondays()->at('13:00');

// Run hourly from 8 AM to 5 PM on weekdays...
$schedule->command('foo')
          ->weekdays()
          ->hourly()
          ->timezone('America/Chicago')
          ->between('8:00', '17:00');

Dưới đây là danh sách các ràng buộc đặt lịch bổ sung:

Phương thức Miêu tả
->weekdays(); Chỉ chạy vào ngày thường
->sundays(); Chỉ chạy vào Chủ Nhật
->mondays(); Chỉ chạy vào thứ Hai
->tuesdays(); Chỉ chạy vào thứ Ba
->wednesdays(); Chỉ chạy vào thứ Tư
->thursdays(); Chỉ chạy vào thứ Năm
->fridays(); Chỉ chạy vào thứ Sáu
->saturdays(); Chỉ chạy vào thứ Bảy
->between($start, $end); Chỉ chạy trong khoảng start và end
->when(Closure); Chạy phụ thuộc vào điều kiện trong
->environments($env); Chạy phụ thuộc vào môi trường cụ thể

Preventing Task Overlaps

Ngăn chặn task chồng chéo. Mặc định, task được đặt lịch sẽ thực hiện thậm chí khi mà lần thực thi trước vẫn còn đang thực hiện. Để chặn việc này, bạn có thể sử dụng hàm withoutOverlapping:

$schedule->command('emails:send')->withoutOverlapping();

Trong ví dụ này, emails:send Artisan command sẽ được thực hiện mỗi phút nếu như chưa được chạy. Hàm withoutOverlapping đặc biệt hữu dụng nếu bạn có task thực hiện không đồng bộ về thời gian, hạn chế việc bạn phải tính toán xem một task tốn mất bao nhiêu thời gian để thực hiện tiếp lần sau.

Running Tasks On One Server

Để sử dụng tính năng này, ứng dụng của bạn phải sử dụng memcached hoặc redis như là bộ nhớ mặc định. Bên cạnh đó, tất cả các servers phải liên kết với cùng một server trung tâm.

Để nhiệm vụ chỉ chạy trên một máy chủ, sử dụng onOneServer khi xác định task đã được lên lịch. Máy chủ đầu tiên có được nhiệm vụ sẽ bảo đảm khóa trong công việc để ngăn các máy chủ khác chạy cùng một task cùng một lúc

$schedule->command('report:generate')
                ->fridays()
                ->at('17:00')
                ->onOneServer();

II. Cách Sử dụng

Step 1: Install Laravel 5.8

Download và cài đặt laravel

composer create-project --prefer-dist laravel/laravel blog

Step 2: Create Command

php artisan make:command DemoCron --command=demo:cron

Sau khi run cmd trên sẽ tạo ra 1 file DemoCron.php với nội dung như dưới.

app/Console/Commands/DemoCron.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class DemoCron extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'demo:cron';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

Chỉnh sửa function handle() như sau:

public function handle()
{
        Log::info("CronDemo is working!");

        /*
          Code here
        */

        $this->info('Demo:Cron Cummand Run successfully!');
}

Step 3: Register on Task Scheduler

app/Console/Kernel.php

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        Commands\DemoCron::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // $schedule->command('inspire')
        //          ->hourly();

        $schedule->command('demo:cron')->everyMinute();
    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}

Step 4: Run Scheduler Command For Test

Để xem cron có chạy đúng không, chúng ta có thể check bằng cmd như sau:

php artisan schedule:run

Sau khi chạy cmd trên, bạn kiểm tra file log, nếu có kết quả log như sau thì job chạy ok.

[2019-06-23 03:16:17] local.INFO: CronDemo is working!  
[2019-06-23 03:16:47] local.INFO: CronDemo is working!  
[2019-06-23 03:16:52] local.INFO: CronDemo is working!  

Hy vọng bài viết sẽ giúp ích cho bạn, thanks.

Nguồn tham khảo: https://laravel.com/docs/5.8/scheduling


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.