如何用RabbitMQ和Swoole实现一个异步任务系统


Posted in PHP onMay 29, 2021

系统介绍

如何用RabbitMQ和Swoole实现一个异步任务系统

从图中可以看到,我们这个系统是一个基于事件的异步任务系统。就是说当一个事件产生时,生产者将事件抛给调度器,调度器负责查询事件下有哪些任务,然后将这些任务丢到相应的队列中,最后由消费者消费任务队列中的任务。

在整个系统中主要分为三大部分

1.事件生产者,即产生消息事件的一方。

2.任务调度器(Scheduler),负责注册事件并调度任务。

3.消费者(Worker),负责消费任务队列中的任务。

事件生产者

事件生产者很简单,在业务系统中直接调用即可,代码如下。

<?php
 
require_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的流程图。

如何用RabbitMQ和Swoole实现一个异步任务系统

可以看到,在这里我们采用了两个交换器和两个队列,一个负责处理正常的任务即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();

自定义调度器

一般来说这是一个基于事件的任务系统,那么能不能直接产生任务呢。答案是肯定的。

只需要创建一个自定义调度器,由您自行实现调度逻辑,最终生成一个任务即可。代码如下:

<?php
 
require_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去执行。

以上就是如何用RabbitMQ和Swoole实现一个异步任务系统的详细内容,更多关于用RabbitMQ和Swoole实现一个异步任务系统的资料请关注三水点靠木其它相关文章!

PHP 相关文章推荐
让你的PHP同时支持GIF、png、JPEG
Oct 09 PHP
php 前一天或后一天的日期
Jun 28 PHP
PHP Curl多线程原理实例详解
Nov 06 PHP
thinkphp区间查询、统计查询与SQL直接查询实例分析
Nov 24 PHP
PHP两种快速排序算法实例
Feb 15 PHP
PHP 读取大文件并显示的简单实例(推荐)
Aug 12 PHP
PHP中多线程的两个实现方法
Oct 14 PHP
PHP实现原生态图片上传封装类方法
Nov 08 PHP
PHP echo()函数讲解
Feb 15 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
Oct 16 PHP
Docker 安装 PHP并与Nginx的部署实例讲解
Feb 27 PHP
PHP7修改的函数
Mar 09 PHP
浅谈Laravel中使用Slack进行异常通知
May 29 #PHP
详解Go与PHP的语法对比
May 29 #PHP
详解php中流行的rpc框架
如何在Mac上通过docker配置PHP开发环境
浅谈如何提高PHP代码质量之端到端集成测试
May 28 #PHP
浅谈如何提高PHP代码质量之单元测试
May 28 #PHP
浅谈如何提高PHP代码的质量
May 28 #PHP
You might like
PHP中数字检测is_numeric与ctype_digit的区别介绍
2012/10/04 PHP
php二维数组排序与默认自然排序的方法介绍
2013/04/27 PHP
php中生成随机密码的自定义函数代码
2013/10/21 PHP
php调用自己java程序的方法详解
2016/05/13 PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
2016/12/12 PHP
javascript 哈希表(hashtable)的简单实现
2010/01/20 Javascript
通用无限极下拉菜单的实现代码
2016/05/31 Javascript
TinyMCE汉化及本地上传图片功能实例详解
2016/05/31 Javascript
jQuery中table数据的值拷贝和拆分
2017/03/19 Javascript
在 Angular6 中使用 HTTP 请求服务端数据的步骤详解
2018/08/06 Javascript
vue自定义tap指令及tap事件的实现
2018/09/18 Javascript
Node.js原生api搭建web服务器的方法步骤
2019/02/15 Javascript
简单了解Vue + ElementUI后台管理模板
2020/04/07 Javascript
vue+高德地图实现地图搜索及点击定位操作
2020/09/09 Javascript
[01:32:22]DOTA2-DPC中国联赛 正赛 Ehome vs VG BO3 第一场 2月5日
2021/03/11 DOTA
Python使用reportlab模块生成PDF格式的文档
2019/03/11 Python
Python实现的服务器示例小结【单进程、多进程、多线程、非阻塞式】
2019/05/23 Python
python射线法判断检测点是否位于区域外接矩形内
2019/06/28 Python
详解django实现自定义manage命令的扩展
2019/08/13 Python
python pyinstaller打包exe报错的解决方法
2019/11/02 Python
pandas 中对特征进行硬编码和onehot编码的实现
2019/12/20 Python
python 实现将Numpy数组保存为图像
2020/01/09 Python
pytorch梯度剪裁方式
2020/02/04 Python
Android本地应用打开方法——通过html5写连接
2016/03/11 HTML / CSS
HTML5之HTML元素扩展(下)—增强的Form表单元素值得关注
2013/01/31 HTML / CSS
HTML5+css3:3D旋转木马效果相册
2017/01/03 HTML / CSS
美国LOGO设计公司:The Logo Company
2018/07/16 全球购物
包装类的功能、种类、常用方法
2012/01/27 面试题
J2ee常用的设计模式?说明工厂模式
2015/05/21 面试题
高级护理专业毕业生推荐信
2013/12/25 职场文书
料理师求职信
2014/01/30 职场文书
进口业务员岗位职责
2014/04/06 职场文书
中学生操行评语
2014/04/24 职场文书
2014年城管工作总结
2014/11/20 职场文书
2016春季幼儿园开学寄语
2015/12/03 职场文书
这样写python注释让代码更加的优雅
2021/06/02 Python