本篇介紹如何在 Laravel 框架中,使用 Schedule 設定排程任務,讓指定的程式碼在特定時間自動執行。
什麼是 Laravel Schedule?
Laravel Schedule 是 Laravel 內建的排程系統,讓你可以直接在程式碼中定義任務與執行頻率,不需要手動編輯 Server 上的 Crontab。
常見使用情境:
- 每日寄送報表 Email
- 定期清除過期資料 / Log
- 每小時同步第三方 API 資料
- 定期產生快取
設定方式(Laravel 11)
Laravel 11 之後,排程直接定義在 routes/console.php:
# routes/console.php use Illuminate\Support\Facades\Schedule; // 每分鐘執行一個 Artisan 指令 Schedule::command('report:daily')->dailyAt('08:00'); // 每小時執行一個 Job Schedule::job(new SyncDataJob)->hourly(); // 每天凌晨清除過期 token Schedule::command('sanctum:prune-expired --hours=24')->daily();
Laravel 10 以前,在 app/Console/Kernel.php 的 schedule() 方法中定義:
# app/Console/Kernel.php
protected function schedule(Schedule $schedule): void
{
$schedule->command('report:daily')->dailyAt('08:00');
$schedule->job(new SyncDataJob)->hourly();
$schedule->command('cache:clear')->weekly();
}
建立自訂 Artisan Command
php artisan make:command SendDailyReport
# app/Console/Commands/SendDailyReport.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Jobs\SendReportEmailJob;
class SendDailyReport extends Command
{
protected $signature = 'report:daily';
protected $description = '寄送每日報表 Email';
public function handle(): void
{
$this->info('開始寄送每日報表...');
SendReportEmailJob::dispatch();
$this->info('完成!');
}
}
常用頻率設定
| 方法 | 說明 |
|---|---|
->everyMinute() |
每分鐘 |
->everyFiveMinutes() |
每 5 分鐘 |
->hourly() |
每小時整點 |
->hourlyAt(30) |
每小時第 30 分鐘 |
->daily() |
每天凌晨 00:00 |
->dailyAt('08:00') |
每天早上 08:00 |
->weekdays() |
只在平日(週一至週五) |
->weekly() |
每週日 00:00 |
->weeklyOn(1, '08:00') |
每週一 08:00 |
->monthly() |
每月 1 號 00:00 |
->cron('0 8 * * 1-5') |
自訂 Cron 表達式 |
進階條件控制
// 只在正式環境執行 Schedule::command('report:daily') ->dailyAt('08:00') ->environments('production'); // 避免重疊執行(前一次還沒跑完就不再啟動) Schedule::command('sync:data') ->everyFiveMinutes() ->withoutOverlapping(); // 在背景執行(不阻塞排程器) Schedule::command('sync:data') ->everyFiveMinutes() ->runInBackground(); // 執行失敗時發送 Email 通知 Schedule::command('report:daily') ->daily() ->emailOutputOnFailure('[email protected]'); // 自訂條件決定是否執行 Schedule::command('report:daily') ->daily() ->when(fn () => config('app.reports_enabled'));
Server 上設定 Crontab
Laravel Schedule 的觸發點只需要在 Server 上設定一條 Crontab,讓 Laravel 自行管理後續所有排程:
# 編輯 crontab crontab -e # 加入以下一行(每分鐘觸發 Laravel Schedule) * * * * * cd /var/www/html/your-project && php artisan schedule:run >> /dev/null 2>&1
使用 Supervisor 管理 Schedule(Laravel 11+)
Laravel 11 新增了 schedule:work 指令,可以讓排程在前景持續運行(每分鐘自動觸發),適合搭配 Supervisor 使用,不需要再設定 Crontab:
# /etc/supervisor/conf.d/schedule.conf
[program:schedule]
command=php /var/www/html/artisan schedule:work
numprocs=1
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/schedule.log
supervisorctl reread supervisorctl update supervisorctl start schedule
本地測試
# 列出所有排程任務 php artisan schedule:list # 立即觸發所有到期的排程(手動測試用) php artisan schedule:run # 持續運行排程(本地開發測試用,每分鐘自動觸發) php artisan schedule:work # 測試單一指令是否正常運作 php artisan report:daily
Crontab vs schedule:work 比較
| 方式 | 設定位置 | 最小單位 | 適合環境 |
|---|---|---|---|
| Crontab | Server crontab | 1 分鐘 | Laravel 10 以下或傳統部署 |
schedule:work + Supervisor |
Supervisor conf | 1 分鐘 | Laravel 11、Docker 環境 |
小結
Laravel Schedule 讓排程任務的管理完全集中在程式碼中,版本控制、部署一次搞定,不需要手動去每台伺服器設定 Crontab。搭配 Supervisor 的 schedule:work,在 Docker 環境下也能輕鬆讓排程穩定常駐運行。
參考文獻: