PHP实现电商订单自动确认收货redis队列


Posted in PHP onMay 17, 2017

一、场景

之前做的电商平台,用户在收到货之后,大部分都不会主动的点击确认收货,导致给商家结款的时候,商家各种投诉,于是就根据需求,要做一个订单在发货之后的x天自动确认收货。所谓的订单自动确认收货,就是在在特定的时间,执行一条update语句,改变订单的状态。

二、思路

最笨重的做法,通过linux后台定时任务,查询符合条件的订单,然后update。最理想情况下,如果每分钟都有需要update的订单,这种方式也还行。奈何平台太小,以及卖家发货时间大部分也是密集的,不会分散在24小时的每分钟。那么,定时任务的话,查询过多,不适合。这里可以先把将要自动确认收货的订单信息存储到其他介质上,比如redis,memcache,rabbitmq,然后执行的脚本从前面的介质获取到订单信息来判断,这里可以大大的减少数据库的查询压力。

redis队列的生产者

对此,我们选择每天在凌晨两点的时候,通过linux的定时任务把即将要确认收货的订单信息查询出来,然后存储在redis上,redis上我们选择的队列,队列处理的特点就是先进先出,前面的数据在查询订单时,通过发货时间排序,所以最先出队列的肯定是距离规定的自动收货时间最近的订单。代码如下

$successCount=0;
$failCount=0;
$screen_time = 3600*24*9;//设置筛选天数
$data = array();
$now_time = time();
//查询符合要求的数据
$sql="select id,send_time as deliver_time from `order` where is_send=1 and is_del=0 and is_cancel=0 and is_token=0 and send_time>0 and send_time + {$screen_time} < $now_time
order by send_time asc";
$res = $con->query($sql);
//当队列还有数据时将数据记录并清除
while($redis->LLEN('auto_recevice_order')){
$txt = '执行时间:'.date('Y-m-d H:i:s').',信息:'.$redis->RPOP('auto_recevice_order');
file_put_contents('./autoToken/fail_log.txt',$txt."\r\n".PHP_EOL,FILE_APPEND);
$failCount++;
}
//重新填充数据进队列
while ($row = $res->fetch_assoc()) {
 $successCount++;
 $redis->LPUSH('auto_recevice_order',json_encode($row1));
}
 $con->close();
 $success=date('Y-m-d H:i:s').':[推送成功]:本次成功推送数据:'.$successCount.'条;记录上次处理失败数据:'.$failCount."条\r\n";
 file_put_contents('./success_log.txt',$success."\r\n".PHP_EOL,FILE_APPEND);

redis队列的消费者

队列的消费者没有通过linux的定时任务去做,用linux的screen+php cli模式执行php脚本,消费者只需要不断的从队列中读取订单信息,然后判断订单信息中的发货时间,如果达到自动收货的要求,就执行update语句。同时如果没有达到收货的时间,而且与收货时间间距比较大的时候,可以让php脚本休眠sleep一定的时间数,这个时间数自己调节设计,获取出来的未达到时间要求的订单,需要重新推送到redis队列中去,而且还是队列的顶端。以便下次获取。代码如下:

$set_time = 3600*24*10;//设置几天后自动收货
while(true){
if($i%30==0){
usleep(10);//防止while 循环使CPU使用率过高
}
if($redis->LLEN('auto_recevice_order')){
$data = json_decode($redis->RPOP('auto_recevice_order'));
$id = (int)$data->id;//将数据转化为整形
$deliver_time = (int)$data->deliver_time;//将数据转化为整形
$res1 = $res2 =false;
$now_time = time();
if(($deliver_time+$set_time)<$now_time){
 $sql1 = "update `order` set `is_token`='1',`token_time` = $now_time where id=$id and is_send=1 and is_del=0 and is_cancel=0 and is_token=0 and send_time + {$set_time} < $now_time";
 $res1 = $con->query($sql1);//更新数据
$rows = mysqli_affected_rows($con);
if($rows){
 $ip = $this->getIp();
 $sql2 = "insert into `order_log`(`order_id`,`log_msg`,`log_ip`,`log_role`,`log_user`,`log_order_state`,`log_time`) VALUES($id,'系统自动收货','$ip','系统','服务器','收货',$now_time)";//写入订单日志
 $res2 = $con->query($sql2);//添加日志数据
 }
 }
 if($res1==false){//将没达到条件的数据重新插入队列中
  $redis->RPUSH('auto_recevice_order',json_encode(array('id'=>$id,'deliver_time'=>$deliver_time)));
 }
}
 $i++;
}

这里执行php脚本,需要用到linux的screen或者supervisor、nohup守护进程。具体用法可自行百度.同样脚本里面最好有必须的日志记录。

三、思考

随着业务的增长,在队列中同一秒内,存在的多个需要处理的订单,而一次只能从队列中取出一个相关订单信息的时候,可以采用一个生产者多个消费者的模式,这种情况下,可以用到锁机制,保证一条消息只能到达一个消费者。当redis数据达到一定的量之后,也可以适当的调整生产者的执行频率和对应的条件。

以上这篇PHP实现电商订单自动确认收货redis队列就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
php中的数组操作函数整理
Aug 18 PHP
php下保存远程图片到本地的办法
Aug 08 PHP
PHP程序员面试 切忌急功近利(更需要注重以后的发展)
Sep 01 PHP
深入掌握include_once与require_once的区别
Jun 17 PHP
windows服务器中检测PHP SSL是否开启以及开启SSL的方法
Apr 25 PHP
php读取csc文件并输出
May 21 PHP
PHP第三方登录―QQ登录实现方法
Feb 06 PHP
yii2使用GridView实现数据全选及批量删除按钮示例
Mar 01 PHP
PHP针对中英文混合字符串长度判断及截取方法示例
Mar 31 PHP
老生常谈PHP中的数据结构:DS扩展
Jul 17 PHP
php常用字符串查找函数strstr()与strpos()实例分析
Jun 21 PHP
php使用自带dom扩展进行元素匹配的原理解析
May 29 PHP
老生常谈PHP面向对象之解释器模式
May 17 #PHP
phpmyadmin下载、安装、配置教程
May 16 #PHP
Windows下php+mysql5.7配置教程
May 16 #PHP
php使用curl实现ftp文件下载功能
May 16 #PHP
PHP jpgraph库的配置及生成统计图表:折线图、柱状图、饼状图
May 15 #PHP
php使用curl实现简单模拟提交表单功能
May 15 #PHP
PHP读取Excel类文件
May 15 #PHP
You might like
php页面跳转代码 输入网址跳转到你定义的页面
2013/03/28 PHP
smarty中常用方法实例总结
2015/08/07 PHP
Laravel+jQuery实现AJAX分页效果
2016/09/14 PHP
PHP流Streams、包装器wrapper概念与用法实例详解
2017/11/17 PHP
基于jquery的二级联动菜单实现代码
2011/04/25 Javascript
jquery ajax例子返回值详解
2012/09/11 Javascript
jquery插件之定时查询待处理任务数量
2014/05/01 Javascript
JS实现距离上次刷新已过多少秒示例
2014/05/23 Javascript
javascript限制文本框输入值类型的方法
2015/05/07 Javascript
js实现黑色简易的滑动门网页tab选项卡效果
2015/08/31 Javascript
浅谈使用MVC模式进行JavaScript程序开发
2015/11/10 Javascript
JQuery移动页面开发之屏幕方向改变与滚屏的实现
2015/12/03 Javascript
JS实现HTML表格排序功能
2016/08/05 Javascript
js判断所有表单项不为空则提交表单的实现方法
2016/09/09 Javascript
Javascript中关于Array.filter()的妙用详解
2016/12/04 Javascript
javascript 判断一个对象为数组的方法
2017/05/03 Javascript
通过jquery获取上传文件名称、类型和大小的实现代码
2018/04/19 jQuery
小程序实现抽奖动画
2020/04/16 Javascript
vue中filters 传入两个参数 / 使用两个filters的实现方法
2019/07/15 Javascript
解决vue语法会有延迟加载显现{{xxx}}的问题
2019/11/14 Javascript
基于vue中的scoped坑点解说
2020/09/04 Javascript
[29:59]完美世界DOTA2联赛PWL S3 Forest vs access 第二场 12.11
2020/12/13 DOTA
Python的Django框架中的数据库配置指南
2015/07/17 Python
JSONLINT:python的json数据验证库实例解析
2017/11/28 Python
使用pygame编写Flappy bird小游戏
2020/03/14 Python
详解Python openpyxl库的基本应用
2021/02/26 Python
Yves Rocher捷克官方网站:植物化妆品的创造者
2019/07/31 全球购物
敏捷开发的主要原则都有哪些
2015/04/26 面试题
医科大学生毕业的自我评价分享
2013/11/12 职场文书
金融事务专业求职信
2014/04/25 职场文书
社区扶贫帮困工作总结
2015/05/20 职场文书
大学运动会通讯稿
2015/07/18 职场文书
四群教育工作总结
2015/08/10 职场文书
2019年干货:自我鉴定
2019/03/25 职场文书
nginx配置虚拟主机的详细步骤
2021/07/21 Servers
使用CSS自定义属性实现骨架屏效果
2022/06/21 HTML / CSS