如何用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 VS ASP
Oct 09 PHP
php读取csv文件后,uft8 bom导致在页面上显示出现问题的解决方法
Aug 10 PHP
php实现mysql封装类示例
May 07 PHP
php之Smarty模板使用方法示例详解
Jul 08 PHP
PHP中IP地址与整型数字互相转换详解
Aug 20 PHP
php定义一个参数带有默认值的函数实例分析
Mar 16 PHP
PHP递归调用数组值并用其执行指定函数的方法
Apr 01 PHP
PHP中读取文件的几个方法总结(推荐)
Jun 03 PHP
PHP入门教程之正则表达式基本用法实例详解(正则匹配,搜索,分割等)
Sep 11 PHP
php-fpm服务启动脚本的方法
Apr 27 PHP
微信公众平台开发教程②微信端分享功能图文详解
Apr 10 PHP
PHP 时间处理类Carbon
May 20 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文件操作实现代码分享
2011/09/01 PHP
php模拟js函数unescape的函数代码
2012/10/20 PHP
PHP漏洞全解(详细介绍)
2012/11/13 PHP
smarty模板引擎基础知识入门
2015/03/30 PHP
PHP自动补全表单的两种方法
2017/03/06 PHP
Flash+XML滚动新闻代码 无图片 附源码下载
2007/11/22 Javascript
js中scrollHeight,scrollWidth,scrollLeft,scrolltop等差别介绍
2012/05/16 Javascript
关于jQuery UI 使用心得及技巧
2012/10/10 Javascript
JavaScript中创建对象和继承示例解读
2014/02/12 Javascript
bootstrapfileinput实现文件自动上传
2016/11/08 Javascript
nodejs中向HTTP响应传送进程的输出
2017/03/19 NodeJs
vue实现微信分享朋友圈,发送朋友的示例讲解
2018/02/10 Javascript
AngularJs返回前一页面时刷新一次前面页面的方法
2018/10/09 Javascript
基于vue和websocket的多人在线聊天室
2020/02/01 Javascript
JavaScript前端实现压缩图片功能
2020/03/06 Javascript
[02:51]2014DOTA2 TI小组赛总结中国军团全部进军钥匙球馆
2014/07/15 DOTA
[01:33:14]LGD vs VP Supermajor 败者组决赛 BO3 第二场 6.10
2018/07/04 DOTA
对于Python中线程问题的简单讲解
2015/04/03 Python
在Python中使用PIL模块对图片进行高斯模糊处理的教程
2015/05/05 Python
举例详解Python中threading模块的几个常用方法
2015/06/18 Python
使用XML库的方式,实现RPC通信的方法(推荐)
2017/06/14 Python
python聚类算法解决方案(rest接口/mpp数据库/json数据/下载图片及数据)
2019/08/28 Python
Python3实现二叉树的最大深度
2019/09/30 Python
PyTorch实现ResNet50、ResNet101和ResNet152示例
2020/01/14 Python
浅谈keras中自定义二分类任务评价指标metrics的方法以及代码
2020/06/11 Python
用CSS3和table标签实现一个圆形轨迹的动画的示例代码
2019/01/17 HTML / CSS
HTML5到底会有什么发展?HTML5的前景展望
2015/07/07 HTML / CSS
HTML5页面中尝试调起APP功能
2017/09/12 HTML / CSS
Marmot土拨鼠官网:美国专业户外运动品牌
2018/01/11 全球购物
三星印度官网:Samsung印度
2019/08/03 全球购物
电子专业毕业生自我鉴定
2014/01/22 职场文书
2014年餐厅服务员工作总结
2014/11/18 职场文书
区域经理岗位职责
2015/02/02 职场文书
Mysql查询时间区间日期列表,不会由于数据表数据影响
2022/04/19 MySQL
如何使用注解方式实现 Redis 分布式锁
2022/07/23 Redis
python playwright之元素定位示例详解
2022/07/23 Python