## **簡介**
傳統的程序執行流程一般是 即時|同步|串行的,在某些場景下,會存在并發低,吞吐量低,響應時間長等問題。在大型系統中,一般會引入消息隊列的組件,將流程中部分任務抽離出來放入消息隊列,并由專門的消費者作針對性的處理,從而降低系統耦合度,提高系統性能和可用性。
一般來說,可以抽離的任務具有以下的特點:
* **允許延后|異步|并行處理**(相對于傳統的**即時|同步|串行**的執行方式)
* **允許延后**:
搶購活動時,先快速緩沖有限的參與人數到消息隊列,后續再排隊處理實際的搶購業務;
* **允許異步**:
業務處理過程中的郵件,短信等通知
* **允許并行**:
用戶支付成功之后,郵件通知,微信通知,短信通知可以由多個不同的消費者并行執行,通知到達的時間不要求先后順序。
* **允許失敗和重試**
* 強一致性的業務放入核心流程處理
* 無一致性要求或最終一致即可的業務放入隊列處理
thinkphp-queue是thinkphp 官方提供的一個消息隊列服務,它支持消息隊列的一些基本特性:
* 消息的**發布**,**獲取**,**執行**,**刪除**,**重發**,**失敗處理**,**延遲執行**,**超時控制**等
* 隊列的**多隊列**,**內存限制**,**啟動**,**停止**,**守護**等
* 消息隊列可**降級為同步執行**
thinkphp-queue 內置了**Redis**,**Database**,**Topthink**,**Sync**這四種驅動。本文主要介紹 thinkphp-queue 結合其內置的 redis 驅動的使用方式和基本原理。
## **安裝**
> composer require topthink/think-queue
## **配置**
> 配置文件位于`config/queue.php`
### 公共配置
~~~
[
'default'=>'sync' //驅動類型,可選擇 sync(默認):同步執行,database:數據庫驅動,redis:Redis驅動//或其他自定義的完整的類名
]
~~~
## **創建任務類**
> 單模塊項目推薦使用`app\job`作為任務類的命名空間 多模塊項目可用使用`app\module\job`作為任務類的命名空間 也可以放在任意可以自動加載到的地方
任務類不需繼承任何類,如果這個類只有一個任務,那么就只需要提供一個`fire`方法就可以了,如果有多個小任務,就寫多個方法,下面發布任務的時候會有區別
每個方法會傳入兩個參數`think\queue\Job $job`(當前的任務對象) 和`$data`(發布任務時自定義的數據)
還有個可選的任務失敗執行的方法`failed`傳入的參數為`$data`(發布任務時自定義的數據)
### 下面寫兩個例子
```
namespace app\job;
use think\queue\Job;
class Job1{
public function fire(Job $job, $data){
//....這里執行具體的任務
if ($job->attempts() > 3) {
//通過這個方法可以檢查這個任務已經重試了幾次了
}
//如果任務執行成功后 記得刪除任務,不然這個任務會重復執行,直到達到最大重試次數后失敗后,執行failed方法
$job->delete();
// 也可以重新發布這個任務
$job->release($delay); //$delay為延遲時間
}
public function failed($data){
// ...任務達到最大重試次數后,失敗了
}
}
```
```
namespace app\lib\job;
use think\queue\Job;
class Job2{
public function task1(Job $job, $data)
{
}
public function task2(Job $job, $data)
{
}
public function failed($data)
{
}
}
```
## **發布任務**
```
// 立即執行
think\facade\Queue::push($job, $data = '', $queue = null)
// 在`$delay`秒后執行
think\facade\Queue::later($delay, $job, $data = '', $queue = null)
```
`$job`是任務名
單模塊的,且命名空間是`app\job`的,比如上面的例子一,寫`Job1`類名即可
多模塊的,且命名空間是`app\module\job`的,寫`model/Job1`即可
其他的需要些完整的類名,比如上面的例子二,需要寫完整的類名`app\lib\job\Job2`
如果一個任務類里有多個小任務的話,如上面的例子二,需要用@+方法名`app\lib\job\Job2@task1`、`app\lib\job\Job2@task2`
`$data`是你要傳到任務里的參數
`$queue`隊列名,指定這個任務是在哪個隊列上執行,同下面監控隊列的時候指定的隊列名,可不填
## **監聽任務并執行**
```
php think queue:listen
php think queue:work
```
兩種,具體的可選參數可以輸入命令加`--help`查看
> 可配合supervisor使用,保證進程常駐