Laravel入坑指南(番外)——任務排程
Laravel提供了非常強勁的命令列工具(如果還不瞭解,傳送到第8往篇),我們如果想要定期執行某個命令列,可以利用crontab進行定時設定。如果有多個定期的任務,很簡單,我們設定多條crontab規則在不同時間段內排程不同的命令即可。
而Laravel框架內部也提供了這樣的排程機制。(當然,還是逃不過crontab的支援)
首先,我們需要在crontab中新增這麼一條規則
* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
其次,所有的排程任務都在/app/Console/Kernel.php的schedule函式中進行排程設定
這個函式中可以排程閉包、可呼叫物件(包含__invoke的物件)、artisian命令、列隊任務以及shell命令。以下以例子進行說明:
//排程閉包,->daily()即排程選項,每天凌晨零點執行任務 //關於排程選項後面會統一說明 $schedule->call(function () { DB::table('recent_users')->delete(); })->daily(); //排程可呼叫物件 //DeleteRecentUsers類中包含了__invoke魔術方法 $schedule->call(new DeleteRecentUsers)->daily();//排程artisian命令 $schedule->command('emails:send --force')->daily(); $schedule->command(EmailsCommand::class, ['--force'])->daily(); //排程列隊任務 $schedule->job(new Heartbeat)->everyFiveMinutes(); $schedule->job(new Heartbeat, 'heartbeats')->everyFiveMinutes(); //將job投遞到heartbeats列隊中 //排程shell命令$schedule->exec('node /home/forge/script.js')->daily();
常用的排程選項:
方法 | 描述 |
->cron('* * * * *'); | 在自定義Cron排程上執行任務 |
->everyMinute(); | 每分鐘執行一次任務 |
->everyFiveMinutes(); | 每五分鐘執行一次任務 |
->everyTenMinutes(); | 每十分鐘執行一次任務 |
->everyFifteenMinutes(); | 每十五分鐘執行一次任務 |
->everyThirtyMinutes(); | 每三十分鐘執行一次任務 |
->hourly(); | 每小時執行一次任務 |
->hourlyAt(17); | 每小時第十七分鐘執行一次任務 |
->daily(); | 每天凌晨零點執行任務 |
->dailyAt('13:00'); | 每天13:00執行任務 |
->twiceDaily(1, 13); | 每天1:00 & 13:00執行任務 |
->weekly(); | 每週執行一次任務 |
->monthly(); | 每月執行一次任務 |
->monthlyOn(4, '15:00'); | 每月4號15:00執行一次任務 |
->quarterly(); | 每個季度執行一次 |
->yearly(); | 每年執行一次 |
->timezone('America/New_York'); | 設定時區 |
額外排程約束選項:
方法 | 描述 |
->weekdays(); | 只在工作日執行任務 |
->weekends(); | 只在週末執行任務 |
->sundays(); | 每個星期天執行任務 |
->mondays(); | 每個星期一執行任務 |
->tuesdays(); | 每個星期二執行任務 |
->wednesdays(); | 每個星期三執行任務 |
->thursdays(); | 每個星期四執行任務 |
->fridays(); | 每個星期五執行任務 |
->saturdays(); | 每個星期六執行任務 |
->between($start, $end); | 基於特定時間段執行任務 |
->when(Closure); | 基於特定測試執行任務 |
->environments($env); | 只在指定環境執行任務 |
舉幾個例子:
// 每週星期一13:00執行一次... $schedule->call(function () { })->weekly()->mondays()->at('13:00'); // 工作日的上午8點到下午5點每小時執行... $schedule->command('foo') ->weekdays() ->hourly() ->timezone('America/Chicago') ->between('8:00', '17:00'); //每天7點到22點之間,每小時執行 $schedule->command('reminders:send') ->hourly() ->between('7:00', '22:00'); //每天23點到4點之外的時間內,每小時執行 $schedule->command('reminders:send') ->hourly() ->unlessBetween('23:00', '4:00'); //when的閉包返回true時執行 $schedule->command('emails:send')->daily()->when(function () { return true; }); //skip的閉包返回false時執行 $schedule->command('emails:send')->daily()->skip(function () { return true; });
第三,任務排程的重疊處理
當下一次任務開始執行時,萬一上一次的任務還沒有執行完成,新的任務是會執行的。也就是說,有可能出現多次任務重疊執行的情況。
為了避免這種情況,我們可以使用外部的手段來加鎖,比如檔案鎖flock,或者redis的setnx都可以。但是Laravel非常貼心,已經幫我們準備了這樣的機制:
$schedule->command('emails:send')->withoutOverlapping(); //鎖預設24小時失效 $schedule->command('emails:send')->withoutOverlapping(10); //鎖10分鐘失效
第四,任務排程的順序
預設情況下,同時排程的多個命令會順序執行。如果你有一些長時間執行的命令,將會導致隨後的命令在預期之後很久才能執行。如果你想要讓命令在後臺執行以便它們可以同時運,可以使用 runInBackground 方法來實現:
$schedule->command('analytics:report') ->daily() ->runInBackground();
第五,任務輸出
我們可以將任務中的輸出重定向覆蓋寫入或追加寫入檔案中,便於問題的排查:
//覆蓋寫入 $schedule->command('emails:send') ->daily() ->sendOutputTo($filePath); //追加寫入 $schedule->command('emails:send') ->daily() ->appendOutputTo($filePath);
最後,任務鉤子
使用 before 和 after 方法,你可以指定在排程任務完成之前和之後要執行的程式碼:
$schedule->command('emails:send') ->daily() ->before(function () { // 任務即將開始... }) ->after(function () { // 任務已經完成... });
好了,Laravel話題到這裡正式結束了。關於Laravel還有一些知識點,如果想要深入瞭解的小夥伴就去看官方文件吧。
下週開始,博主會進入另一個話題。至於要寫什麼,嗯,還沒想好,大家下週再見:)
--------------------------- 我是可愛的分割線 ----------------------------
最後博主借地宣傳一下,漳州程式設計小組招新了,這是一個面向漳州青少年資訊學/軟體設計的學習小組,有意向的同學點選連結,聯絡我吧。