[TOC]
### **1、簡介**
在以前,開發者需要為每一個需要[調度](http://laravelacademy.org/tags/%e8%b0%83%e5%ba%a6 "View all posts in 調度")的[任務](http://laravelacademy.org/tags/%e4%bb%bb%e5%8a%a1 "View all posts in 任務")編寫一個[Cron](http://laravelacademy.org/tags/cron "View all posts in Cron")條目,這是很讓人頭疼的事。你的任務調度不在源碼控制中,你必須使用SSH登錄到服務器然后添加這些Cron條目。[Laravel](http://laravelacademy.org/tags/laravel "View all posts in Laravel")命令調度器允許你平滑而又富有表現力地在Laravel中定義命令調度,并且服務器上只需要一個Cron條目即可。
任務調度定義在`app/[Console](http://laravelacademy.org/tags/console "View all posts in Console")/Kernel.php`文件的`schedule`方法中,該方法中已經包含了一個示例。你可以自由地添加你需要的調度任務到`Schedule`對象。
#### **開啟調度**
下面是你唯一需要添加到服務器的Cron條目:
~~~
* * * * * php /path/to/artisan schedule:run 1>> /dev/null 2>&1
~~~
該Cron將會每分鐘調用Laravel命令調度,然后,Laravel評估你的調度任務并運行到期的任務。
### **2、定義調度**
你可以在`App\Console\Kernel`類的`schedule`方法中定義所有調度任務。開始之前,讓我們看一個調度任務的例子,在這個例子中,我們將會在每天午夜調度一個被調用的閉包。在這個閉包中我們將會執行一個數據庫查詢來清空表:
~~~
<?php
namespace App\Console;
use DB;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel{
/**
* 應用提供的Artisan命令
*
* @var array
*/
protected $commands = [
'App\Console\Commands\Inspire',
];
/**
* 定義應用的命令調度
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->call(function () {
DB::table('recent_users')->delete();
})->daily();
}
}
~~~
除了調度閉包調用外,還可以調度[Artisan命令](http://laravelacademy.org/post/3106.html)和操作系統命令。例如,可以使用`command`方法來調度一個Artisan命令:
~~~
$schedule->command('emails:send --force')->daily();
~~~
`exec`命令可用于發送命令到操作系統:
~~~
$schedule->exec('node /home/forge/script.js')->daily();
~~~
#### **2.1 調度常用選項**
當然,你可以分配多種調度到任務:
| 方法 | 描述 |
| --- | --- |
| `->cron('* * * * *');` | 在自定義Cron調度上運行任務 |
| `->everyMinute();` | 每分鐘運行一次任務 |
| `->everyFiveMinutes();` | 每五分鐘運行一次任務 |
| `->everyTenMinutes();` | 每十分鐘運行一次任務 |
| `->everyThirtyMinutes();` | 每三十分鐘運行一次任務 |
| `->hourly();` | 每小時運行一次任務 |
| `->daily();` | 每天凌晨零點運行任務 |
| `->dailyAt('13:00');` | 每天13:00運行任務 |
| `->twiceDaily(1, 13);` | 每天1:00 & 13:00運行任務 |
| `->weekly();` | 每周運行一次任務 |
| `->monthly();` | 每月運行一次任務 |
| `->quarterly();` | 每個季度運行一次 |
| `->yearly();` | 每年運行一次 |
這些方法可以和額外的約束一起聯合起來創建一周特定時間運行的更加細粒度的調度,例如,要每周一調度一個命令:
~~~
$schedule->call(function () {
// 每周星期一13:00運行一次...
})->weekly()->mondays()->at('13:00');
~~~
下面是額外的調度約束列表:
| 方法 | 描述 |
| --- | --- |
| `->weekdays();` | 只在工作日運行任務 |
| `->sundays();` | 每個星期天運行任務 |
| `->mondays();` | 每個星期一運行任務 |
| `->tuesdays();` | 每個星期二運行任務 |
| `->wednesdays();` | 每個星期三運行任務 |
| `->thursdays();` | 每個星期四運行任務 |
| `->fridays();` | 每個星期五運行任務 |
| `->saturdays();` | 每個星期六運行任務 |
| `->when(Closure);` | 基于特定測試運行任務 |
##### **基于測試的約束條件**
`when`方法用于限制任務在通過給定測試之后運行。換句話說,如果給定閉包返回`true`,只要沒有其它約束條件阻止任務運行,該任務就會執行:
~~~
$schedule->command('emails:send')->daily()->when(function () {
return true;
});
~~~
reject方法和when相反,如果reject方法返回true,調度任務將不會執行:
~~~
$schedule->command('emails:send')->daily()->reject(function () {
return true;
});
~~~
使用when方法鏈的時候,調度命令將只會執行返回true的when方法。
#### **2.2 避免任務重疊**
默認情況下,即使前一個任務仍然在運行調度任務也會運行,要避免這樣的情況,可使用`withoutOverlapping`方法:
~~~
$schedule->command('emails:send')->withoutOverlapping();
~~~
在本例中,Artisan命令`emails:send`每分鐘都會運行,如果該命令沒有在運行的話。如果你的任務在執行時經常大幅度的變化,那么`withoutOverlapping`方法就非常有用,你不必再去預測給定任務到底要消耗多長時間。
### **3、任務[輸出](http://laravelacademy.org/tags/%e8%be%93%e5%87%ba "View all posts in 輸出")**
Laravel調度器為處理調度任務輸出提供了多個方便的方法。首先,使用`sendOutputTo`方法,你可以發送輸出到文件以便稍后檢查:
~~~
$schedule->command('emails:send')
->daily()
->sendOutputTo($filePath);
~~~
如果你想要追加輸出到給定文件,可以使用appendOutputTo方法:
~~~
$schedule->command('emails:send')
->daily()
->appendOutputTo($filePath);
~~~
使用`emailOutputTo`方法,你可以將輸出發送到電子郵件,注意輸出必須首先通過`sendOutputTo`方法發送到文件。還有,使用電子郵件發送任務輸出之前,應該配置Laravel的[電子郵件服務](http://laravelacademy.org/post/3239.html):
~~~
$schedule->command('foo')
->daily()
->sendOutputTo($filePath)
->emailOutputTo('foo@example.com');
~~~
> 注意:`emailOutputTo`和`sendOutputTo`方法只對`command`方法有效,不支持`call`方法。
### **4、任務鉤子**
使用`before`和`after`方法,你可以指定在調度任務完成之前和之后要執行的代碼:
~~~
$schedule->command('emails:send')
->daily()
->before(function () {
// Task is about to start...
})
->after(function () {
// Task is complete...
});
~~~
##### **ping URL**
使用`pingBefore`和`thenPing`方法,調度器可以在任務完成之前和之后自動ping給定的URL。該方法在通知外部服務時很有用,例如[Laravel Envoyer](https://envoyer.io/),在調度任務開始或完成的時候:
~~~
$schedule->command('emails:send')
->daily()
->pingBefore($url)
->thenPing($url);
~~~
使用`pingBefore($url)`或`thenPing($url)`特性需要安裝HTTP庫Guzzle,可以在`composer.json`?文件中添加如下行來安裝Guzzle到項目:
~~~
"guzzlehttp/guzzle": "~5.3|~6.0"
~~~
- 序言
- 發行版本說明
- 升級指南
- 貢獻代碼
- 開始
- 安裝
- 配置
- Laravel Homestead
- 基礎
- HTTP 路由
- HTTP 中間件
- HTTP 控制器
- HTTP 請求
- HTTP 響應
- 視圖
- Blade 模板引擎
- 架構
- 一次請求的生命周期
- 應用目錄結構
- 服務提供者
- 服務容器
- 門面(Facades)
- 數據庫
- 起步
- 查詢構建器
- 遷移
- 填充數據
- Eloquent ORM
- 起步
- 關聯關系
- 集合
- 訪問器&修改器
- 序列化
- 服務
- 用戶認證
- 用戶授權
- Artisan Console
- 訂閱支付實現:Laravel Cashier
- 緩存
- 集合
- 集成前端資源:Laravel Elixir
- 加密
- 錯誤&日志
- 事件
- 文件系統/云存儲
- 哈希
- 輔助函數
- 本地化
- 郵件
- 包開發
- 分頁
- Redis
- 隊列
- Session
- Envoy Task Runner
- 任務調度
- 測試
- 驗證
- 新手入門指南
- 簡單任務管理系統
- 帶用戶功能的任務管理系統