Task Scheduling

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.

Bộ lệnh đặt lịch của Laravel cho phép bạn định nghĩa 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. Nếu bạn không biết thêm Cron vào server, xem tại Laravel Forge nó có thể giúp bạn biết cách thêm Cron:

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

Dòng Cron này sẽ gọi tới bộ lệnh thực hiện lịch của Laravel mỗi phút. Khi schedule:run được thực thi, Laravel sẽ kiểm tra các task đã được lên lịch và thực thi các task cần thực hiện.

Đị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 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 = [
        \App\Console\Commands\Inspire::class,
    ];

    /**
     * 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();
    }
}

Ngoài việc đặt lịch cho Closure, bạn cũng có thể đặt lịch cho Artisan commands và các lệnh hệ thống. Ví dụ, bạn có thể sử dụng hàm command để đặt lịch cho một câu lệnh Artisan như sau:

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

$schedule->command(EmailsCommand::class, ['--force'])->daily();

Lệnh exec có thể được sử dụng để thực thi một câu lệnh trong hệ điều hành:

$schedule->exec('node /home/forge/script.js')->daily();

Tuỳ chọn tần suất Schedule

Tất nhiên, có vài kiểu đặt lịch bạn có thể thiết lập cho task:

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
->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
->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

Ràng buộc khoảng thời gian

Hàm between có thể sử dụng để giới hạn thời gian thực thi task trong ngày:

$schedule->command('reminders:send')
                    ->hourly()
                    ->between('7:00', '22:00');

Tương tự, hàm unlessBetween có thể dùng để loại trừ thực thi một task trong khoảng thời gian:

$schedule->command('reminders:send')
                    ->hourly()
                    ->unlessBetween('23:00', '4:00');

Kiểm tra ràng buộc

Hàm when có thể được sử dụng để giới hạn thực thi của một task dựa trên kết quả kiểm tra mệnh đề trong Closure trả về true, task sẽ thực thi nếu như không có điều kiện ràng buộc nào ngăn chặn:

$schedule->command('emails:send')->daily()->when(function () {
    return true;
});

Hàm skip có thể coi là ngược lại đối với when. Nếu hàm skiptrả về true, ttask sẽ không được thực thi:

$schedule->command('emails:send')->daily()->skip(function () {
    return true;
});

Khi sử dụng phối hợp với when, câu lệnh đặt lịch sẽ chỉ thực thi khi mà các điều kiện when trả về true.

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 đều 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.

Task Output

Bộ đặt lịch của Laravel cung cấp vài hàm tiện tích để làm việc với output sinh ra bởi các task. Đầu tiên là hàm sendOutputTo, bạn có thể đẩy output tới một file để tìm hiểu sau:

$schedule->command('emails:send')
         ->daily()
         ->sendOutputTo($filePath);

Nếu bạn muốn chèn thêm output vào một file, bạn có thể sử dụng appendOutputTo:

$schedule->command('emails:send')
         ->daily()
         ->appendOutputTo($filePath);

Sử dụng hàm emailOutputTo, bạn có thể gửi email về output tới địa chỉ bạn muốn. Chú ý là output phải được lưu vào một file sử dụng sendOutputTo trước. Thêm nữa, trước khi gửi mail, bạn phải cấu hình e-mail services:

$schedule->command('foo')
         ->daily()
         ->sendOutputTo($filePath)
         ->emailOutputTo('foo@example.com');

Hàm emailOutputTo, sendOutputToappendOutputTo không sử dụng được với hàm command và không hỗ trợ cho hàm call.

Task Hooks

Sử dụng hàm beforeafter, bạn có thể chỉ định đoạn code cần thực hiện trước vào sau khi task hoàn thiện:

$schedule->command('emails:send')
         ->daily()
         ->before(function () {
             // Task is about to start...
         })
         ->after(function () {
             // Task is complete...
         });

Pinging URLs

Sử dụng hàm pingBeforethenPing , bộ đặt lịch có thể tự động gửi ping tới một URL trước và sau khi một task hoàn thiện. Hàm này khá hữu ích cho việc gửi thông báo tới một dịch vụ bên ngoài, ví dụ như Laravel Envoyer, để cho biết là task của bạn đã bắt đầu hay hoàn thiện:

$schedule->command('emails:send')
         ->daily()
         ->pingBefore($url)
         ->thenPing($url);

Sử dụng pingBefore($url) hoặc thenPing($url) yêu cầu thư viện Guzzle HTTP. Vì thế, bạn cần thêm Guzzle vào trong project bằng cách thêm dòng sau vào trong:

composer require guzzlehttp/guzzle
Nguồn: https://laravel.com/docs/5.3/scheduling