Redis消息队列与thinkphp/queue操作

业务场景

场景一

用户完成注册后需要发送欢迎注册的问候邮件、同时后台要发送实时消息给用户对应的业务员有新的客户注册、最后将用户的注册数据通过接口推送到一个营销用的第三方平台。

遇到两个问题:
  1. 由于代码是串行方式,流程大致为:开启数据库事务回滚->数据入库准备->发邮件->发实时消息->推送第三方平台->提交写入数据库。但是后续的3个步骤任意一个流程出了问题都会影响用户的注册结果。
  2. 发送邮件使用的不是成熟的第三方产品,而是利用phpmaile自写代码实现的,然而这个过程耗时相对较长且偶尔有失败的情况;另外通过接口推送注册用户数据到的第三方平台是一个国外的产品接口通讯时间很长且一样有失败的情况。
以上两个问题就会导致用户的注册交互流程时间很长产品体验感非常差;且发送邮件、发送消息、推送数据任意一个步骤由于特殊情况导致执行失败都不能终止用户注册这样就只能通过日志捕获相应的失败情况。

场景二

用户在Shopify平台(一个跨境电商平台)付款下单后,商家会将订单同步到我的系统中,在我的系统中完成询价、报价、付款后我需要再将订单数据推送到第三方配货发货的平台。平台发货完成后通过设置好的回调地址通知我的系统发货的物流信息数据,我需要将物流信息数据存入到我的数据库后再将物流信息同步给Shopify平台用以展示给真实下单用户查看物流轨迹。

遇到一个问题:
  1. 正常情况下的回调代码逻辑是将物流信息写入数据库,再同步物流数据给Shopify。但是由于各种原因后者(同步物流数据给Shopify)有一定概率会失败。
这样就出现了我系统内成功展示了物流信息而Shopify反馈没有成功同步物流轨迹的订单出现。而回调又是一次性的我只能自查数据库进行回补。

英雄登场(消息队列Redis)

官方介绍:消息队列中间件是大型系统中的重要组件,已经逐渐成为企业系统内部通信的核心手段。它具有松耦合、异步消息、流量削峰、可靠投递、广播、流量控制、最终一致性等一系列功能,已经成为异步RPC的主要手段之一。

Redis安装

我用的宝塔安装的方便快捷,软件商品搜索Redis然后点击系统对应php版本的立即前往
在这里插入图片描述
再后续弹窗中安装redis扩展即可
在这里插入图片描述
后续Redis中的队列数据也可以通过宝塔进行查看:
在这里插入图片描述

thinkphp/queue

扩展这个内置了 Redis、Database、Topthink、Sync四种驱动,这里我用的Redis。think-queue 队列消息可以进行任务的发布、获取、执行、删除、重新发布、延迟发布、超时控制等操作。

thinkphp/queue引入扩展

composer require topthink/think-queue

thinkphp/queue配置文件

我使用的是TP5要再application/extra目录下新增queue.php文件,文件内容如下(视各自情况调整哈):

return ['connector'  => 'Redis', // 驱动类型'expire'     => 60, // 任务的过期时间,默认为60秒; 如果任务执行时间超过此时间将会被认为是过期,将不会被执行'default'    => 'default', // 默认的队列名称'host'       => '127.0.0.1', // Redis 主机地址'port'       => 6379, // Redis 端口'password'   => '', // Redis 密码'select'     => 0, // 使用哪一个 Redis 数据库'timeout'    => 0, // 连接超时时间'persistent' => false, // 是否长连接
];

解决方案(注册部分)

引入消息队列后就是将原来串行方式改为并行,用户注册逻辑代码中关于后三个步骤只要单纯的推送队列即可。而后三者采用并行方式(也就是异步)执行对应的逻辑。这样既提高了注册的速度又可以通过队列将出错的数据多次执行提高成功率

注册逻辑代码

	public static function doSaveRegister($postParam){db()->startTrans();try {$first_name = trim(outputstr($postParam, "first_name"));$last_name = trim(outputstr($postParam, "last_name"));$email = trim(outputstr($postParam, "email"));$password = trim(outputstr($postParam, "password"));//注册部分就展示部分代码了$info = new UserModel();$info->id = Uuid::uuid4();$info->number = createUserNumber();$info->short_name = substr($email, 0, strripos($email, "@"));$info->email = $email;if ($info->save() === false) {throw new Exception('Operation error!');}//发送用户注册成功的问候邮件,将要发送邮件的邮箱推送到消息队列$result = RedisUtils::redisQueueSendForSendRegisterWelcomeEmail('common\job\UserRegisterJob@sendRegisterSuccessWelcomeEmail', $email);if ($result['success'] === false) {throw new Exception('redis queue error!');}//这里只展示发送邮件的代码示例其他都是一样的道理db()->commit();$result = result_success('Register successful!');} catch (Exception $e) {db()->rollback();$result = result_error($e->getMessage());}return $result;}

推送发送邮件消息队列(生产者)

	/*** 用户注册成功需要发送问候邮件的用户数据加入队列* @param string $job 处理该任务的任务名* @param string $data 加入队列的数据-邮箱号* @param string $queue_name 队列名,可以不写*/public static function redisQueueSendForSendRegisterWelcomeEmail($job, $data, $queue_name = 'user_register_email'){//此处做了延时推送,原因是邮件服务是自己写程序实现的避免高并发导致发送失败,所以延时推送一下$isPushed = Queue::later(5, $job, $data, $queue_name);if ($isPushed !== false) {$result = result_success('队列加入成功');} else {$result = result_error('队列加入失败');}return $result;}

消息队列处理逻辑(消费者)

<?phpnamespace common\job;use common\utils\email\EmailUtils;
use common\utils\gateway\GatewaysUtils;
use common\utils\log\LoggerUtils;
use common\utils\systemMessage\SystemMessageUtils;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use think\queue\Job;/*** 处理所有用户注册方面的队列数据,代码逻辑写在这里,运行方式是命令行执行的* Class UserRegister* @package common\job*/
class UserRegisterJob
{/*** 处理发送用户注册成功邮件的队列* @param Job $job* @param string $data 要发送邮件的邮箱*/public function sendRegisterSuccessWelcomeEmail(Job $job, $data){$result = EmailUtils::sendUserRegisterSuccessEmail($data);if ($result['success'] === false) {//判断一下发送失败的次数,超过3次剔除队列$attempts = $job->attempts();if ($attempts > 3) {//发送失败,写进日志,邮件通知开发者$message = '新用户注册发送问候邮件失败,程序错误内容:' . $result['msg'] . ',数据源:' . $data;LoggerUtils::systemErrorLog()->info($message);EmailUtils::sendSystemErrorEmailToDeveloper($message);$job->delete();}} else {//发送成功,剔除队列$job->delete();}}
}

启动队列监听

进入项目根目录执行

php think queue:work --queue 队列名1,队列名2

多个队列可以用逗号拼接一次性监听

这个进行一般都要后台运行且开机自启动,自己写的脚本如下:

#!/bin/bash
#启动Redis队列监听
cd /www/wwwroot/english-e-commerce/ && php think queue:listen --queue user_register_email,user_register_workman_message,sync_user_to_tidio,order_sync_mabang_track,fulfillment_shopify_order &

开机启动方法根据不同linux系统有很多种此处不做记录

不喜勿喷,也是初学。记录一下方便后面查找

参考链接

  • ThinkPHP 使用 think-queue 实现 redis 消息队列(超详细)
  • 消息队列使用的四种场景介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/285611.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频号小店月入5w+,真的有那么赚钱吗?

我是电商珠珠 视频号小店是22年视频号团队发展的电商平台&#xff0c;距离现在也不过一年多的时间。我做电商已经有五年左右的时间了&#xff0c;天猫、快手、抖音小店都做过。在22年的时候&#xff0c;我开始琢磨起了视频号小店。 到现在我也拥有了视频号小店的运营团队&…

【C++从练气到飞升】06---重识类和对象

&#x1f388;个人主页&#xff1a;库库的里昂 ✨收录专栏&#xff1a;C从练气到飞升 &#x1f389;鸟欲高飞先振翅&#xff0c;人求上进先读书。 目录 ⛳️推荐 一、再谈构造函数 1. 构造函数体赋值 2. 初始化列表 每个成员变量在初始化列表中只能出现一次--初始化只能初始…

python爬虫学习第二天----类型转换

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

leetcode LCR121.寻找目标值-二维数组

目录 问题描述示例具体思路思路一思路二 代码实现 问题描述 m*n 的二维数组 plants 记录了园林景观的植物排布情况&#xff0c;具有以下特性&#xff1a; 每行中&#xff0c;每棵植物的右侧相邻植物不矮于该植物&#xff1b; 每列中&#xff0c;每棵植物的下侧相邻植物不矮于该…

Hive SQL必刷练习题:留存率问题(*****)

留存率&#xff1a; 首次登录算作当天新增&#xff0c;第二天也登录了算作一日留存。可以理解为&#xff0c;在10月1号登陆了。在10月2号也登陆了&#xff0c;那这个人就可以算是在1号留存 今日留存率 &#xff08;今日登录且明天也登录的用户数&#xff09; / 今日登录的总…

一些恶意样本的流量分析学习

Trickbot Trickbot 是一种自 2016 年以来一直在感染受害者的信息窃取者和银行恶意软件。Trickbot通过恶意垃圾邮件&#xff08;malspam&#xff09;分发&#xff0c;也由其他恶意软件&#xff08;如Emotet&#xff0c;IcedID或Ursnif&#xff09;分发。 分析来自恶意垃圾邮件…

银行5G短消息应用架构设计

&#xff08;一&#xff09;RCS简介 1.1 RCS的提出与标准制定 RCS(Rich Communication Services & Suite&#xff0c;富媒体通信)是GSMA(Groupe Speciale Mobile Association&#xff0c;全球移动通信系统协会)在2008年提出的一种通讯方式&#xff0c;RCS融合了语音、消息…

Bytebase 2.14.1 - 分支 (Branching) 功能支持 Oracle

&#x1f680; 新功能 分支 (Branching) 功能支持 Oracle。为 SQL 编辑器添加了项目选择器。 新增 SQL 审核规范&#xff1a; 禁止混合 DDL、DML 语句。禁止对同一张表进行不同类型的 DML 变更 (UPDATE,INSERT,DELETE)。 &#x1f514; 重大变更 工作空间设置中的「数据访问…

【已解决】MySQL:常用的除法运算+精度处理+除数为0处理

目录 问题现象&#xff1a; 问题分析&#xff1a; 拓展&#xff1a; 1、除法运算&#xff1a; 拓展&#xff1a;MySQL中常用的几种除法运算 1、取整除法 2、浮点数除法 3、取余除法 4、向上取整除法 5、向下取整除法 2、运算结果的精度处理 1.1、浮点数 1.2、总位数 1.3、…

电脑哥的励志创业路:蹭别人的电脑做抖店

我是王路飞。 没有一步到位的创业项目&#xff0c;也没有一击必中的解决方法&#xff0c;有的只是需要时刻解决的当下问题。 做事/创业/成长/生活/人生&#xff0c;都不要追求百分百的圆满&#xff0c;不要抱有一帆风顺的幻想&#xff0c;不要期待十全十美的结果。 它们的第…

Visual Studio QT6 工程引入组件模块,例如:QtXml

QT 工程引入 QtXml QT 版本 6.6.1 Visual Studio 版本 Microsoft Visual Studio Community 2022 (64 位) - Current 版本 17.7.5 打开 Visual Studio 项目工程选择 工具栏 - 扩展 - QT VS Tools -Qt Project Settings 勾选 xml 后点击确定 点击应用即可 注意&#xff1a;配置环…

day44 动态规划part6

完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 完全背包和01背包问题唯一不同…

外部普米集中监控多个Prometheus实例:Prometheus Agent 模式与Prometheus 联邦模式 超级详细

外部普米集中监控多个Prometheus实例 Prometheus Agent 模式-使用推送方式来监控1.外部Prometheus配置1.需要开放端口&#xff0c;在启动时&#xff0c;需要配置开放监听端口2.添加prometheus启动参数3.修改配置后重启prometheus即可 2.各个节点的普米配置1.修改prometheus.yml…

HiveSQL一本通 - 案例实操

文章目录 0.HiveSQL一本通使用说明6.综合案例练习之基础查询6.1 环境准备创建数据表数据准备加载数据 6.2 简单查询练习1.查询姓名中带“山”的学生名单2.查询姓“王”老师的个数3.检索课程编号为“04”且分数小于60的学生的分数信息&#xff0c;结果按分数降序排列4.查询数学成…

vue.js——学习计划表

1&#xff09;准备工作 ①打开D:\vue\chapter02\ learning_schedule 目录&#xff0c;找到 index.html 文件。 在文件中引 入BootStrap 样式文件&#xff0c;具体代码如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8&qu…

【Linux】权限管理

文章目录 前言1.权限访问者的分类2.文件类型与访问权限3.文件权限值的表达方式4.文件访问权限的相关设置5.file指令6.目录权限理解与漏洞7.粘滞位的理解 前言 Linux下有两种用户&#xff1a;超级用户(root)和普通用户 超级用户&#xff1a;可以再linux系统下做任何事情&#x…

Vue3 + Vite + TS + Element-Plus + Pinia项目(3)--新建路由

1、在src文件夹下新建router文件夹后&#xff0c;创建index.ts文件 2、具体如下 import { createRouter, createWebHashHistory } from vue-routerconst router createRouter({history: createWebHashHistory(),routes: [{path: "/index",component: () > impor…

关于YOLOv9项目中使用已有模块自由改进的教程

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 1. 文件说明 在YOLOv5-v9&#xff0c;模型的结构是以yaml文件的存储。我们可以在原有的yaml基础上增、减、改模块&#xff0c;创作我们自己的模型。 …

ASM四部曲之一:什么是ASM

文章目录 前言什么是.class文件什么是ASM概述作用域模型基于ASM的程序架构 ASM库结构 前言 本文翻译自ASM官方文档。 什么是.class文件 Java字节码文件&#xff08;.class&#xff09;是Java编译器编译Java源文件&#xff08;.java&#xff09;产生的目标文件。它是一种8位字…

基于SpringBoot+Layui的社区物业管理系统

项目介绍 社区物业管理系统是基于java程序开发,本系统分为业主和管理员两个角色 业主可以登陆系统,查看车位费用信息,查看物业费用信息,在线投诉,查看投诉,在线报修; 管理员可以车位收费信息,物业收费信息,投诉信息,楼宇信息,房屋信息,业主信息,车位信息,抄表信…