+1

Task Scheduling trong Laravel

Giới thiệu

  • Trước đây, có thể bạn đã từng tạo một Cron cho một tác vụ nào đó mà bạn muốn lập lịch để chạy trên server của bạn. Tuy nhiên, sẽ khá phiền phức nếu bạn muốn thay đổi hoặc thêm các schedules mới khi bạn phải SSH đến server của bạn để thực hiện việc này.
  • Lệnh scheduler của Laravel cho phép bạn xác định lịch trình của mình một cách dễ dàng ngay trong chính Laravel. Khi sử dụng scheduler, bạn chỉ cần duy nhất một 1 lệnh Cron trên server của bạn. Lịch trình làm việc của bạn sẽ được định nghĩa trong phương thức schedule trên file app/Console/Kernel.php. Để giúp bạn bắt đầu, một ví dụ đơn giản được định nghĩa trong phương thức.
  • VD : Với Task Scheduling, bạn có thể dễ dàng định lịch các tác vụ như gửi email hàng ngày, xóa các bản ghi cũ, cập nhật dữ liệu từ các nguồn bên ngoài và nhiều hơn nữa. Laravel cung cấp một cú pháp đơn giản để định nghĩa các tác vụ và lịch trình chúng, đảm bảo rằng các tác vụ được thực hiện đúng thời gian và đúng cách.

1.Khởi tạo Schedules

Bạn có thể khởi tạo các scheduled task trong method schedule trong class App\Console\Kernel. Ví dụ dưới đây là 1 schedule task chạy query xoá table vào mỗi ngày:

<?php
 
namespace App\Console;
 
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\DB;
 
class Kernel extends ConsoleKernel
{
    /**
     * 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 cách sử dụng Closure khi khai báo schedule, bạn cũng có thể gọi đến một PHP class bất kì mà có chưa __invoke() method:

$schedule->call(new DeleteRecentUsers)->daily();

Để xem tổng quan các Scheduled tasks và thời gian tiếp theo mà nó sẽ chạy bạn có thể sử dụng câu lệnh command sau:

php artisan schedule:list

image.png

2. Scheduling cho artisan command

Bạn cũng có thể lên lịch chạy cho các lệnh command bằng cách truyền trực tiếp câu lệnh command hoặc truyền class của command đó:

use App\Console\Commands\SendEmailsCommand;
 
$schedule->command('emails:send Taylor --force')->daily();
 
$schedule->command(SendEmailsCommand::class, ['Taylor', '--force'])->daily();

Khi sử dụng tên class thì các argument bạn muốn truyền vào sẽ phải dưới dạng array

3. Scheduling Queued Jobs

Để lên lịch đưa 1 job nào đó vào hàng đợi queue, bạn dùng tới job method. Ví dụ như sau:

use App\Jobs\Heartbeat;
 
$schedule->job(new Heartbeat)->everyFiveMinutes();

4. Scheduling Shell Commands

Ngoài ra bạn cũng có thể lên lịch cho 1 lệnh command bất kì:

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

5. Các tuỳ chọn custom thời gian Scheduling

Các tuỳ chọn về tần suất thực hiện:

Method Description
->cron('* * * * *'); Run the task on a custom cron schedule
->everyMinute(); Run the task every minute
->everyTwoMinutes(); Run the task every two minutes
->everyThreeMinutes(); Run the task every three minutes
->everyFourMinutes(); Run the task every four minutes
->everyFiveMinutes(); Run the task every five minutes
->everyTenMinutes(); Run the task every ten minutes
->everyFifteenMinutes(); Run the task every fifteen minutes
->everyThirtyMinutes(); Run the task every thirty minutes
->hourly(); Run the task every hour
->hourlyAt(17); Run the task every hour at 17 minutes past the hour
->everyOddHour(); Run the task every odd hour
->everyTwoHours(); Run the task every two hours
->everyThreeHours(); Run the task every three hours
->everyFourHours(); Run the task every four hours
->everySixHours(); Run the task every six hours
->daily(); Run the task every day at midnight
->dailyAt('13:00'); Run the task every day at 13:00
->twiceDaily(1, 13); Run the task daily at 1:00 & 13:00
->twiceDailyAt(1, 13, 15); Run the task daily at 1:15 & 13:15
->weekly(); Run the task every Sunday at 00:00
->weeklyOn(1, '8:00'); Run the task every week on Monday at 8:00
->monthly(); Run the task on the first day of every month at 00:00
->monthlyOn(4, '15:00'); Run the task every month on the 4th at 15:00
->twiceMonthly(1, 16, '13:00'); Run the task monthly on the 1st and 16th at 13:00
->lastDayOfMonth('15:00'); Run the task on the last day of the month at 15:00
->quarterly(); Run the task on the first day of every quarter at 00:00
->quarterlyOn(4, '14:00'); Run the task every quarter on the 4th at 14:00
->yearly(); Run the task on the first day of every year at 00:00
->yearlyOn(6, 1, '17:00'); Run the task every year on June 1st at 17:00
->timezone('America/New_York'); Set the timezone for the task

Ngoài các tuỳ chọn trên bạn có thể kết hợp thêm các ràng buộc sau đây để tạo schedule chặt chẽ hơn :

Method Description
->weekdays(); Limit the task to weekdays
->weekends(); Limit the task to weekends
->sundays(); Limit the task to Sunday
->mondays(); Limit the task to Monday
->tuesdays(); Limit the task to Tuesday
->wednesdays(); Limit the task to Wednesday
->thursdays(); Limit the task to Thursday
->fridays(); Limit the task to Friday
->saturdays(); Limit the task to Saturday
->days(array - mixed); Limit the task to specific days
->between($startTime, $endTime); Limit the task to run between start and end times
->unlessBetween($startTime, $endTime); Limit the task to not run between start and end times
->when(Closure); Limit the task based on a truth test
->environments($env); Limit the task to specific environments

Ví dụ:

Lên lịch vào các ngày trong tuần : Chạy hàng giờ vào CN và T4

$schedule->command('emails:send')
                ->hourly()
                ->days([0, 3]);

Giữa 1 khoảng thời gian : Chạy hàng giờ trong khoảng thời gian từ 7:00 đến 22:00

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

Dựa vào điều kiện : Khi điều kiện đúng thì thực thi

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

Dựa vào môi trường

$schedule->command('emails:send')
            ->daily()
            ->environments(['staging', 'production']);

6. Ngăn việc chồng chéo task

Theo mặc định các task đã được lên lịch sẽ chạy mà không cần đợi task trước đó đã chạy xong hay chưa. Nên để ngăn việc đó bạn có thể sử dụng đến method withoutOverlapping:

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

Mặc định sẽ là sau 24h sau khi task trước đó kết thúc thì mới chạy đến task tiếp theo, nên bạn có thể khai báo thêm thời gian tuỳ chọn:

$schedule->command('emails:send')->withoutOverlapping(10);
  • Thưc chất việc này sử dụng đến cache để lưu biến lock. Đại loại như khi 1 task được chạy 1 biến lock sẽ được lưu vào cache, sau khi hoàn thành thì biến đó sẽ bị xoá đi. Nếu task tiếp theo chạy sẽ cần check biến lock đó có tồn tại hay không thì mới được chạy tiếp.
  • Nên nếu trường hợp có task nào đó bị kẹt thì bạn có thể xoá cache để khắc phục: schedule:clear-cache

Có thể vẫn chạy schedule cả khi ứng dụng trong maintenance mode : $schedule->command('emails:send')->evenInMaintenanceMode();

7. Chạy schedule

Môi trường server: để bắt đầu chạy schedule trên môi trường server bạn sử dụng lệnh với cú pháp như sau:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

image.png

Môi trường local : Chỉ cần chạy câu lệnh artisan sau:

php artisan schedule:work


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í