如何用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 EOT定界符的使用详解
Sep 30 PHP
PHP实现异步调用方法研究与分享
Oct 27 PHP
php网上商城购物车设计代码分享
Feb 15 PHP
Smarty局部缓存的几种方法简介
Jun 17 PHP
php基于str_pad实现卡号不足位数自动补0的方法
Nov 12 PHP
php实现屏蔽掉黑帽SEO的搜索关键字
Apr 15 PHP
基于PHP实现的事件机制实例分析
Jun 18 PHP
如何用PHP来实现一个动态Web服务器
Jul 29 PHP
PHP curl模拟登录带验证码的网站
Nov 30 PHP
PHP的Yii框架中创建视图和渲染视图的方法详解
Mar 29 PHP
PHP命令行执行整合pathinfo模拟定时任务实例
Aug 12 PHP
php如何实现不借助IDE快速定位行数或者方法定义的文件和位置
Jan 17 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/06/24 PHP
php记录日志的实现代码
2011/08/08 PHP
解析web文件操作常见安全漏洞(目录、文件名检测漏洞)
2013/06/29 PHP
YII框架实现自定义第三方扩展操作示例
2019/04/26 PHP
laravel 框架结合关联查询 when()用法分析
2019/11/22 PHP
jquery判断checkbox(复选框)是否被选中的代码
2010/10/20 Javascript
jQuery实现仿腾讯迷你首页选项卡效果代码
2015/09/17 Javascript
jQuery超简单选项卡完整实例
2015/09/26 Javascript
Bootstrap风格的WPF样式
2016/12/07 Javascript
基于BootStrap栅格栏系统完成网站底部版权信息区
2016/12/23 Javascript
js实现颜色阶梯渐变效果(Gradient算法)
2017/03/21 Javascript
Nodejs搭建wss服务器教程
2017/05/24 NodeJs
谈谈JavaScript中super(props)的重要性
2019/02/12 Javascript
C#程序员入门学习微信小程序的笔记
2019/03/05 Javascript
jQuery HTML设置内容和属性操作实例分析
2020/05/20 jQuery
在vue中created、mounted等方法使用小结
2020/07/21 Javascript
基于js实现的图片拖拽排序源码实例
2020/11/04 Javascript
跟老齐学Python之从if开始语句的征程
2014/09/14 Python
Python 2.7.x 和 3.x 版本的重要区别小结
2014/11/28 Python
Python通过递归遍历出集合中所有元素的方法
2015/02/25 Python
Python中实现变量赋值传递时的引用和拷贝方法
2018/04/29 Python
浅谈python的dataframe与series的创建方法
2018/11/12 Python
基于python实现KNN分类算法
2020/04/23 Python
Python判断字符串是否xx开始或结尾的示例
2019/08/08 Python
将Pytorch模型从CPU转换成GPU的实现方法
2019/08/19 Python
HTML5上传文件显示进度的实现代码
2012/08/30 HTML / CSS
HTML5页面音视频在微信和app下自动播放的实现方法
2016/10/20 HTML / CSS
英国儿童家具专卖店:GLTC
2016/09/24 全球购物
意大利比基尼品牌:MISS BIKINI
2019/11/02 全球购物
法语专业求职信
2014/07/20 职场文书
化学工程专业求职信
2014/08/10 职场文书
八项规定个人对照检查材料思想汇报
2014/09/25 职场文书
数据库连接池
2021/04/06 MySQL
关于redisson缓存序列化几枚大坑说明
2021/08/04 Redis
Ruby处理CSV数据方法详解
2022/04/18 Ruby
Python如何将list中的string转换为int
2022/07/15 Ruby