如何用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读取MySQL数据代码
Jun 05 PHP
php加密算法之实现可逆加密算法和解密分享
Jan 21 PHP
PHP结合JQueryJcrop实现图片裁切实例详解
Jul 24 PHP
thinkphp模板赋值与替换实例简述
Nov 24 PHP
php限制上传文件类型并保存上传文件的方法
Mar 13 PHP
php实现每天自动变换随机问候语的方法
May 12 PHP
使用WordPress发送电子邮件的相关PHP函数用法解析
Dec 15 PHP
php轻松实现文件上传功能
Mar 03 PHP
thinkphp框架实现删除和批量删除
Jun 29 PHP
ThinkPHP框架整合微信支付之Native 扫码支付模式二图文详解
Apr 09 PHP
PHP连接SQL server数据库测试脚本运行实例
Aug 24 PHP
PHP使用Redis队列执行定时任务实例讲解
Mar 24 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自动反斜杠的函数代码
2010/01/05 PHP
php获取网页标题和内容函数(不包含html标签)
2014/02/03 PHP
几个比较实用的JavaScript 测试及效验工具
2010/04/18 Javascript
Easy.Ajax 部分源代码 支持文件上传功能, 兼容所有主流浏览器
2011/02/24 Javascript
JavaScript常用对象的方法和属性小结
2012/01/24 Javascript
js判断浏览器类型的方法
2013/08/07 Javascript
JavaScript移除数组内重复元素的方法
2015/03/18 Javascript
Javascript中的方法和匿名方法实例详解
2015/06/13 Javascript
浅析AngularJS中的生命周期和延迟处理
2015/06/18 Javascript
深入理解关于javascript中apply()和call()方法的区别
2016/04/12 Javascript
关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法
2016/05/17 Javascript
jQuery ajax调用后台aspx后台文件的两种常见方法(不是ashx)
2016/06/28 Javascript
利用three.js画一个3D立体的正方体示例代码
2017/11/19 Javascript
基于$.ajax()方法从服务器获取json数据的几种方式总结
2018/01/31 Javascript
跨域请求两种方法 jsonp和cors的实现
2018/11/11 Javascript
koa-router路由参数和前端路由的结合详解
2019/05/19 Javascript
vue中使用elementUI组件手动上传图片功能
2019/12/13 Javascript
解决vue-photo-preview 异步图片放大失效的问题
2020/07/29 Javascript
原生js中运算符及流程控制示例详解
2021/01/05 Javascript
[07:40]DOTA2每周TOP10 精彩击杀集锦vol.4
2014/06/25 DOTA
Python判断两个对象相等的原理
2017/12/12 Python
Python实现繁体中文与简体中文相互转换的方法示例
2018/12/18 Python
python实现批量文件重命名
2019/10/31 Python
基于python生成英文版词云图代码实例
2020/05/16 Python
python:HDF和CSV存储优劣对比分析
2020/06/08 Python
Flask中jinja2的继承实现方法及实例
2021/03/03 Python
HTML5的标签的代码的简单介绍 HTML5标签的简介
2012/05/28 HTML / CSS
使用html5制作loading图的示例
2014/04/14 HTML / CSS
Wojas罗马尼亚网站:波兰皮鞋品牌
2018/11/01 全球购物
2014年情人节活动方案
2014/02/16 职场文书
《盲人摸象》教学反思
2014/02/16 职场文书
2015年敬老院工作总结
2015/05/18 职场文书
音乐剧猫观后感
2015/06/04 职场文书
2016大一新生军训感言
2015/12/08 职场文书
2016简历自荐信优秀范文
2016/01/29 职场文书
css3中2D转换之有趣的transform形变效果
2022/02/24 HTML / CSS