基於RabbitMQ和Swoole實現的一個完整的非同步任務系統

來源:互聯網
上載者:User
從最開始的使用http://www.php.cn/wiki/1504.html" target="_blank">redis實現的單進程消費的非同步任務系統到加入swoole的多進程消費模式,現在,我們的非同步任務系統終於又能邁進一步。

因為有了前面兩個簡單系統的經驗,這回基於RabbitMQ的非同步任務系統設計的的更加完善,包括多進程消費,異常重試等。

系統介紹


消費端架構圖

可以看到,我們這個系統是一個基於事件的非同步任務系統。就是說當一個事件產生時,生產者將事件拋給調度器,調度器負責查詢事件下有哪些任務,然後將這些任務丟到相應的隊列中,最後由消費者消費任務隊列中的任務。

在整個系統中主要分為三大部分

1.事件生產者,即產生訊息事件的一方。
2.任務調度器(Scheduler),負責註冊事件並調度任務。
3.消費者(Worker),負責消費任務隊列中的任務。

事件生產者

事件生產者很簡單,在業務系統中直接調用即可,代碼如下。

<?phprequire_once DIR.'/../autoload.php';use Asynclib\Ebats\Event;try{    $event = new Event('order_paied');  //定義事件    $event->setOptions(['order_id' => 'FB138020392193312']); //事件產生的參數    $event->publish();}catch (Exception $exc){    echo $exc->getMessage();}

任務調度器

調度器主要做兩件事,一是註冊事件,另一個是調度任務。

註冊事件代碼如下:

//註冊事件EventManager::register('order_create', 'closeOrder', 'demo', 10);//關閉未付款訂單(延遲任務)EventManager::register('order_paied', 'virtualShipping', 'demo'); //虛擬商品自動發貨

這樣就註冊了兩個事件,事件下各有一個任務。

具體調度部分代碼很簡單,就不多贅述,有興趣的可以去看代碼。

消費者

重頭戲來了,一個非同步任務系統最重要的就是消費端了,現在讓我們來看下Worker的流程圖。


一個完整的消費進程

可以看到,在這裡我們採用了兩個交換器和兩個隊列,一個負責處理正常的任務即ntask,另一個負責處理需要順延強制的任務即dtask。簡單描述下一個任務的生命週期。

正常任務

1、task產生,進入正常任務的交換器Exchange[ebats_core_ntask]
2、交換器根據topic將任務分發到對應的隊列中
3、子進程ntask阻塞等待成功擷取到task,並執行該任務
4、執行失敗,需要重試時拋出RetryException,不需要重試時拋出TaskException
5、子進程ntask捕獲到重試異常將任務拋給延遲任務的交換器Exchange[ebats_core_dtask]
6、將任務執行資訊回調給上層開發人員以便儲存查看

延遲任務

1、子進程dtask阻塞等待成功擷取到task,並執行該任務
2、執行失敗,需要重試時拋出RetryException,不需要重試時拋出TaskException
3、子進程dtask捕獲到重試異常將任務拋給延遲任務的交換器Exchange[ebats_core_dtask]
4、將任務執行資訊回調給上層開發人員以便儲存查看

消費者代碼如下:

require_once DIR.'/../autoload.php';require_once DIR.'/task/TaskDemoModel.php';use Asynclib\Ebats\Worker;//執行結果回呼函數$callback = function ($topic, $taskid, $taskname, $params, $timeuse, $message){};$worker = new Worker($callback);  //支援多進程消費預設為1$worker->setQueue('demo');  //隊列名和事件的topic一一對應$worker->run();

自訂調度器

一般來說這是一個基於事件的任務系統,那麼能不能直接產生任務呢。答案是肯定的。

只需要建立一個自訂調度器,由您自行實現調度邏輯,最終產生一個任務即可。代碼如下:

<?phprequire_once DIR.'/../autoload.php';use Asynclib\Ebats\Task;use Asynclib\Core\Consumer;use Asynclib\Amq\ExchangeTypes;use Asynclib\Exception\ExceptionInterface;/**  * 本樣本示範了如何建立一個自訂調度器,開發人員可以根據自身需求開發自己的任務調度器 */try{    $worker = new Consumer();    $worker->setExchange('order_fanout', ExchangeTypes::TOPIC);    $worker->setQueue('shzf_order_paied', ['*.*.WAIT_SELLER_SEND_GOODS']);    $worker->run(function($key, $msg){        $order_data = json_encode($msg);        echo " [$key] $order_data \n";        Task::create('demo', 'orderAsync', $msg);//建立任務,之後訊息將作為參數由任務接管處理    });}catch (ExceptionInterface $exc){    echo $exc->getMessage();}

這樣,當接收到訊息時就會產生一個orderAsync的任務,您只需要啟動一個用來消費這個Topic的Worker即可。

也許你會覺得這裡直接寫商務邏輯的代碼就可以了,實際上也確實可以。當你可以忍受一個進程慢慢消費的時候是可以這樣做的。但大多數情況下我們還是希望它能夠儘快的消費掉,所以建議這裡只負責建立任務,具體任務的商務邏輯由worker去執行。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.