Trong quá khứ, có thể bạn đã tạo ra Cron cho một task schedule mà bạn cần để server của bạn chạy. Tuy nhiên, điều này có thể nhanh chóng trở thành một vấn đề lớn, bởi vì task schedule của bạn không có trong source code nên bạn phải SSH vào server và thêm các Cron vào bằng một cách thủ công.
Lệnh schedule của Laravel cho phép bạn định nghĩa một cách đơn giản và rõ ràng các lệnh đó trong chính Laravel của bạn. Khi sử dụng schedule, chỉ cần một Cron duy nhất trên server của bạn. Các task schedule của bạn sẽ được định nghĩa trong phương thức schedule
ở file app/Console/Kernel.php
. Để giúp bạn bắt đầu, một ví dụ mẫu đơn giản đã được định nghĩa sẵn trong phương thức đó.
Khi sử dụng schedule, bạn chỉ cần thêm Cron dưới đây vào server của bạn. Nếu bạn không biết cách thêm Cron vào server của bạn, hãy xem xét sử dụng một dịch vụ như Laravel Forge để có thể quản lý Cron cho bạn:
* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
Cron này sẽ gọi lệnh schedule của Laravel mỗi phút. Khi lệnh schedule:run
được thực thi, Laravel sẽ tìm các task theo schedule của bạn và chạy các task đã đến hạn.
Bạn có thể định nghĩa tất cả các task đã được schedule của bạn trong phương thức schedule
của class App\Console\Kernel
. Để bắt đầu, chúng ta hãy xem một ví dụ về schedule cho một task. Trong ví dụ này, chúng ta sẽ schedule một Closure
được gọi mỗi ngày vào lúc nửa đêm. Trong Closure
, chúng ta sẽ thực hiện một truy vấn vào cơ sở dữ liệu để xóa 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 = [
//
];
/**
* 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ạo schedule cho Closure, bạn cũng có thể tạo schedule cho Lệnh Artisan và các lệnh của hệ điều hành. Ví dụ, bạn có thể sử dụng phương thức command
để tạo schedule cho lệnh Artisan bằng cách sử dụng tên hoặc class của command đó:
$schedule->command('emails:send --force')->daily();
$schedule->command(EmailsCommand::class, ['--force'])->daily();
Phương thức job
có thể được sử dụng để tạo schedule cho một queued job. Phương thức này cung cấp một cách thuận tiện để tạo schedule job mà không cần phải sử dụng phương thức call
để tạo Closure cho queue job:
$schedule->job(new Heartbeat)->everyFiveMinutes();
Phương thức exec
có thể được sử dụng để ra lệnh cho hệ điều hành:
$schedule->exec('node /home/forge/script.js')->daily();
Tất nhiên, sẽ có nhiều schedule mà bạn có thể khai báo cho task của bạn:
Method | Description |
---|---|
->cron('* * * * * *'); |
Chạy task theo một tùy chỉnh Cron schedule |
->everyMinute(); |
Chạy task mỗi phút |
->everyFiveMinutes(); |
Chạy task năm phút một lần |
->everyTenMinutes(); |
Chạy task mười phút một lần |
->everyFifteenMinutes(); |
Chạy task mười lăm phút một lần |
->everyThirtyMinutes(); |
Chạy task ba mươi phút một lần |
->hourly(); |
Chạy task một giờ một lần |
->hourlyAt(17); |
Chạy task một giờ một lần vào phút thứ 17 |
->daily(); |
Chạy task hàng ngày |
->dailyAt('13:00'); |
Chạy task hàng ngày vào lúc 13:00 |
->twiceDaily(1, 13); |
Chạy task hàng ngày vào lúc 1:00 và 13:00 |
->weekly(); |
Chạy task hàng tuần |
->monthly(); |
Chạy task hàng tháng |
->monthlyOn(4, '15:00'); |
Chạy task hàng ngày vào ngày thứ 4 của tháng và vào lúc 15:00 |
->quarterly(); |
Chạy task hàng quý |
->yearly(); |
Chạy task hàng năm |
->timezone('America/New_York'); |
Set timezone |
Các phương thức này có thể được kết hợp thêm các ràng buộc để tạo ra các schedule có thể được điều chỉnh tốt hơn, ví dụ như chỉ chạy vào một số ngày nhất định trong tuần. Để schedule một lệnh chạy vào thứ hai hàng tuần thì bạn có thể làm như sau:
// 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 schedule có thể được thêm:
Method | Description |
---|---|
->weekdays(); |
Giới hạn task chỉ chạy vào các ngày trong tuần |
->sundays(); |
Giới hạn task chỉ chạy vào chủ nhật |
->mondays(); |
Giới hạn task chỉ chạy vào thứ hai |
->tuesdays(); |
Giới hạn task chỉ chạy vào thứ ba |
->wednesdays(); |
Giới hạn task chỉ chạy vào thứ tư |
->thursdays(); |
Giới hạn task chỉ chạy vào thứ năm |
->fridays(); |
Giới hạn task chỉ chạy vào thứ sáu |
->saturdays(); |
Giới hạn task chỉ chạy vào thứ bảy |
->between($start, $end); |
Giới hạn task chỉ chạy chỉ chạy vào giữa thời gian start và end |
->when(Closure); |
Giới hạn task chỉ chạy trên một điều kiện đúng |
Phương thức between
có thể được sử dụng để giới hạn việc thực thi của một task dựa vào một khoảng thời gian có trong ngày:
$schedule->command('reminders:send')
->hourly()
->between('7:00', '22:00');
Tương tự, phương thức unlessBetween
có thể được sử dụng để chạy ngược lại việc thực thi của một task trong một khoảng thời gian:
$schedule->command('reminders:send')
->hourly()
->unlessBetween('23:00', '4:00');
Phương thức when
có thể được sử dụng để hạn chế việc thực hiện một task dựa trên kết quả của một điều kiện nhất định. Nói cách khác, nếu Closure
đã cho trả về giá trị true
, tác vụ sẽ thực thi, miễn là không có điều kiện ràng buộc nào khác ngăn task đó chạy:
$schedule->command('emails:send')->daily()->when(function () {
return true;
});
Phương thức skip
có thể được xem là ngược lại với phương thức when
. Nếu phương thức skip
trả về giá trị true
, scheduled task đó sẽ không được thực thi:
$schedule->command('emails:send')->daily()->skip(function () {
return true;
});
Khi sử dụng kết hợp nhiều phương thức when
, lệnh đã được schedule sẽ chỉ được thực thi nếu tất cả các điều kiện when
đều trả về giá trị true
.
Mặc định, các task đã được schedule sẽ được chạy, ngay cả khi instance trước đó của task vẫn đang được chạy. Để ngăn điều này xảy ra, bạn có thể sử dụng phương thức withoutOverlapping
:
$schedule->command('emails:send')->withoutOverlapping();
Ở ví dụ trên, Lệnh Artisan emails:send
sẽ được chạy mỗi phút nếu nó chưa được chạy. Phương thức withoutOverlapping
đặc biệt hữu ích nếu bạn có một task phức tạp cần nhiều thời gian để thực hiện, và bạn không thể dự đoán chính xác task đó sẽ mất bao nhiêu thời gian để hoàn thành.
Nếu cần, bạn có thể chỉ định số phút mà sau khi task được thực hiện thì khóa "chống lặp" hết hạn. Mặc định, khóa này sẽ hết hạn sau 24 giờ:
$schedule->command('emails:send')->withoutOverlapping(10);
Các scheduled task của Laravel sẽ không được chạy khi Laravel ở trong chế độ bảo trì, vì chúng tôi không muốn các task của bạn gây trở ngại với bất kỳ bảo trì nào mà bạn đang thực hiện trên server chưa được hoàn thành. Tuy nhiên, nếu bạn muốn task chạy ngay cả trong chế độ bảo trì, bạn có thể sử dụng phương thức evenInMaintenanceMode
:
$schedule->command('emails:send')->evenInMaintenanceMode();
Laravel schedule cung cấp một số phương thức thuận tiện để làm việc với output được tạo ra bởi schedule task. Đầu tiên, bằng cách sử dụng phương thức sendOutputTo
, bạn có thể gửi output tới một file để kiểm tra sau khi chạy:
$schedule->command('emails:send')
->daily()
->sendOutputTo($filePath);
Nếu bạn muốn thêm output vào một file đã có, bạn có thể sử dụng phương thức appendOutputTo
:
$schedule->command('emails:send')
->daily()
->appendOutputTo($filePath);
Sử dụng phương thức emailOutputTo
, bạn có thể gửi email output đến một địa chỉ email mà bạn đã chọn. Trước khi gửi email output của một task, bạn nên cấu hình e-mail services của Laravel:
$schedule->command('foo')
->daily()
->sendOutputTo($filePath)
->emailOutputTo('[email protected]');
{note} Các phương thức
emailOutputTo
,sendOutputTo
vàappendOutputTo
sẽ chỉ được dùng với phương thứccommand
và không hỗ trợ cho phương thứccall
.
Sử dụng các phương thức before
và after
, bạn có thể khai báo các code mà sẽ được thực thi trước và sau khi scheduled task hoàn tất:
$schedule->command('emails:send')
->daily()
->before(function () {
// Task is about to start...
})
->after(function () {
// Task is complete...
});
Sử dụng các phương thức pingBefore
và thenPing
, schedule có thể tự động ping đến một URL đã cho trước hoặc sau khi task được hoàn tất. Phương thức này sẽ hữu ích để thông báo cho một dịch vụ bên ngoài, chẳng hạn như Laravel Envoyer, rằng scheduled task của bạn đang bắt đầu hoặc đã kết thúc:
$schedule->command('emails:send')
->daily()
->pingBefore($url)
->thenPing($url);
Sử dụng tính năng pingBefore($url)
hoặc thenPing($url)
sẽ cần thư viện Guzzle HTTP. Bạn có thể thêm thư viện Guzzle này vào dự án của bạn bằng trình quản lý package Composer:
composer require guzzlehttp/guzzle
entry