如何用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 相关文章推荐
linux php mysql数据库备份实现代码
Mar 10 PHP
php 字符串替换的方法
Jan 10 PHP
解析argc argv在php中的应用
Jun 24 PHP
windows下PHP_intl.dll正确配置方法(apache2.2+php5.3.5)
Jan 14 PHP
微信公众号点击菜单即可打开并登录微站的实现方法
Nov 14 PHP
php include类文件超时问题处理
Feb 06 PHP
整理php防注入和XSS攻击通用过滤
Sep 13 PHP
PHP防止刷新重复提交页面的示例代码
Nov 11 PHP
PHP递归获取目录内所有文件的实现方法
Nov 01 PHP
php断点续传之文件分割合并详解
Dec 13 PHP
PHP实现的curl批量请求操作示例
Jun 06 PHP
php5.3/5.4/5.5/5.6/7常见新增特性汇总整理
Feb 27 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
FCKeditor的安装(PHP)
2007/01/13 PHP
php 表单数据的获取代码
2009/03/10 PHP
laravel请求参数校验方法
2019/10/10 PHP
js宝典学习笔记(上)
2007/01/10 Javascript
获取网站跟路径的javascript代码(站点及虚拟目录)
2009/10/20 Javascript
IE中getElementsByName()对有些元素无效的解决方案
2014/09/28 Javascript
javascript简单实现图片预加载
2014/12/03 Javascript
JavaScript中Textarea滚动条不能拖动的解决方法
2015/12/15 Javascript
使用JavaScript触发过渡效果的方法
2017/01/19 Javascript
js 原型对象和原型链理解
2017/02/09 Javascript
基于substring()和substr()的使用以及区别(实例讲解)
2017/12/28 Javascript
vue 2.1.3 实时显示当前时间,每秒更新的方法
2018/09/16 Javascript
vue 实现边输入边搜索功能的实例讲解
2018/09/16 Javascript
详解webpack之图片引入-增强的file-loader:url-loader
2018/10/08 Javascript
教你如何编写Vue.js的单元测试的方法
2018/10/17 Javascript
微信小程序冒泡事件及其阻止方法实例分析
2018/12/06 Javascript
Vue组件间通信方法总结(父子组件、兄弟组件及祖先后代组件间)
2019/04/17 Javascript
[44:50]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 TNC vs VG
2018/04/02 DOTA
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
python日志记录模块实例及改进
2017/02/12 Python
Python2和Python3中print的用法示例总结
2017/10/25 Python
python生成器/yield协程/gevent写简单的图片下载器功能示例
2019/10/28 Python
亚洲在线旅行门户网站:Expedia.com.hk(智游网)
2020/04/14 全球购物
俄罗斯品牌服装和鞋子在线商店:BRIONITY
2020/03/26 全球购物
基督教婚礼主持词
2014/03/14 职场文书
农村改厕实施方案
2014/03/22 职场文书
目标管理责任书
2014/04/15 职场文书
公司委托书怎么写
2014/08/02 职场文书
地震捐款倡议书
2014/08/29 职场文书
学习退步检讨书
2014/09/28 职场文书
2015公务员年度考核评语
2015/03/25 职场文书
Python3 多线程(连接池)操作MySQL插入数据
2021/06/09 Python
MySQL中的隐藏列的具体查看
2021/09/04 MySQL
Java 通过手写分布式雪花SnowFlake生成ID方法详解
2022/04/07 Java/Android
MySQL数据库表约束讲解
2022/06/21 MySQL
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers