如何用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中输出转义JavaScript代码的实现代码
Apr 22 PHP
PHP下使用CURL方式POST数据至API接口的代码
Feb 14 PHP
PHP autoload与spl_autoload自动加载机制的深入理解
Jun 05 PHP
php计算几分钟前、几小时前、几天前的几个函数、类分享
Apr 09 PHP
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2611816 bytes)
Nov 08 PHP
PHP获取一段文本显示点阵宽度和高度的方法
Mar 12 PHP
PHP图形操作之Jpgraph学习笔记
Dec 25 PHP
基于PHP实现简单的随机抽奖小程序
Jan 05 PHP
关于php中一些字符串总结
May 05 PHP
PHP API接口必备之输出json格式数据示例代码
Jun 27 PHP
详解PHP变量传值赋值和引用赋值变量销毁
Mar 23 PHP
关于PHP求解三数之和问题详析
Nov 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
第一节--面向对象编程
2006/11/16 PHP
Discuz! Passport 通行证整合
2008/03/27 PHP
php 字符串中的\n换行符无效、不能换行的解决方法
2014/04/02 PHP
适用于抽奖程序、随机广告的PHP概率算法实例
2014/04/09 PHP
浅析php工厂模式
2014/11/25 PHP
基于ThinkPHP实现的日历功能实例详解
2017/04/15 PHP
自制PHP框架之设计模式
2017/05/07 PHP
tp5.1框架数据库子查询操作实例分析
2020/05/26 PHP
基于JQuery的数字改变的动画效果--可用来做计数器
2010/08/11 Javascript
js通过googleAIP翻译PHP系统的语言配置的实现代码
2011/10/17 Javascript
js监控IE火狐浏览器关闭、刷新、回退、前进事件
2014/07/23 Javascript
实现js保留小数点后N位的代码
2014/11/13 Javascript
JavaScript常用的弹出广告及背投广告实现方法
2015/02/06 Javascript
浅谈javascript获取元素transform参数
2015/07/24 Javascript
jQuery 1.9.1源码分析系列(十五)动画处理之缓动动画核心Tween
2015/12/03 Javascript
js实现背景图自适应窗口大小
2017/01/10 Javascript
很棒的一组js图片轮播特效
2017/01/12 Javascript
[js高手之路]原型式继承与寄生式继承详解
2017/08/28 Javascript
React根据宽度自适应高度的示例代码
2017/10/11 Javascript
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
2021/01/22 Vue.js
Python中input与raw_input 之间的比较
2017/08/20 Python
python list转置和前后反转的例子
2019/08/26 Python
Python算法中的时间复杂度问题
2019/11/19 Python
python 实现dict转json并保存文件
2019/12/05 Python
Python加速程序运行的方法
2020/07/29 Python
酒店服务与管理毕业生求职信
2013/11/02 职场文书
12岁生日感言
2014/01/21 职场文书
应聘文员自荐信范文
2014/03/11 职场文书
质量保证书
2015/01/17 职场文书
我们的节日端午节活动总结
2015/02/11 职场文书
人力资源部岗位职责
2015/02/11 职场文书
劳动仲裁调解书
2015/05/20 职场文书
《我在为谁工作》:工作的质量往往决定生活的质量
2019/12/27 职场文书
nginx location中多个if里面proxy_pass的方法
2021/03/31 Servers
教你解决往mysql数据库中存入汉字报错的方法
2021/05/06 MySQL
Goland使用Go Modules创建/管理项目的操作
2021/05/06 Golang