#### 使用
- 服務端啟動worker服務,用于消費隊列任務
```bash
php zcswooe.php queue start|stop|kill
```
- 客戶端調用方式:
```php
RedisDB::getConnection()->lPush('queue_name', json_encode([
'router' => '/queue/test/save',
'params' => [['value1', 'value2'], ['key'=>'value3'], 'value4']
]));
```
隊列內容必須包括兩個參數router和params,具體參數如下:
- router表示任務處理的控制器路由,路由的解析和http服務的路由解析一樣,例如/user/saveContent表示調用app/controllers/userController的saveContent方法,即隊列的任務可以直接調用http控制器的方法處理,具體參考router解析
- params表示控制器方法參數,params必須是一個數組,參考call_user_func_array參數
- 如上,任務的處理將由testController控制器處理,相當于:
```php
$controller = new app/controllers/queue/testController();
$controller->save(['value1', 'value2'], ['key'=>'value3'], 'value4')
```
#### 實現
- swoole_timer + swoole_process + redis(rabbitmq)
#### 流程

流程圖

運行圖
#### 簡單說明
- 原理參考: https://github.com/kcloze/swoole-jobs
- 一個隊列可以有多個worker來處理任務,一個worker即一個子進程
- 一個隊列可以設置最小worker數,最大worker數,當隊列積壓的任務數超過指定峰值之后,便會動態新增worker處理任務,總數量不超過最大worker數
- 一個隊列總會保持最小worker數處理任務數,動態新增的worker在處理完指定任務數之后便會退出
- 父進程(即master主進程)負責子進程的啟動和動態添加,負責子進程退出之后處理(swoole_wait)
- 子進程負責處理對應的隊列的任務
- 異步定時器(swoole_timer),指定周期內檢測隊列積壓數量,根據積壓數值來決定是否新增worker來處理任務
#### 信號處理器
- SIGCHLD: 子進程退出觸發SIGCHLD信號,處理子進程退出
- SIGINT: 終端強制退出(ctrl + c)
- SIGTERM: 強制終止進程退出(kill mpid)
- SIGUSR1: 平滑退出進程,等待子進程處理完任務后退出,退出時間由定時器周期決定
#### 注意問題
- 多個進程不能共享一個數據連接
- 子進程創建之后,會得到父進程一個副本,所以子進程不能共享全局變量或其他類型變量,所以子進程需要共享父進程狀態,需要將父進程狀態寫到第三方類庫(文件,數據庫等等)
- 子進程退出后,父進程務必要執行swoole_process::wait進行回收,否則這個子進程就會變為僵尸進程。會浪費操作系統的進程資源。
#### 主要代碼文件
- /zcswoole/command/QueueCommand.php