一、场景
之前做的电商平台,用户在收到货之后,大部分都不会主动的点击确认收货,导致给商家结款的时候,商家各种投诉,于是就根据需求,要做一个订单在发货之后的x天自动确认收货。所谓的订单自动确认收货,就是在在特定的时间,执行一条update语句,改变订单的状态。
二、思路
最笨重的做法,通过linux后台定时任务,查询符合条件的订单,然后update。最理想情况下,如果每分钟都有需要update的订单,这种方式也还行。奈何平台太小,以及卖家发货时间大部分也是密集的,不会分散在24小时的每分钟。那么,定时任务的话,查询过多,不适合。这里可以先把将要自动确认收货的订单信息存储到其他介质上,比如redis,memcache,rabbitmq,然后执行的脚本从前面的介质获取到订单信息来判断,这里可以大大的减少数据库的查询压力。
redis队列的生产者
对此,我们选择每天在凌晨两点的时候,通过linux的定时任务把即将要确认收货的订单信息查询出来,然后存储在redis上,redis上我们选择的队列,队列处理的特点就是先进先出,前面的数据在查询订单时,通过发货时间排序,所以最先出队列的肯定是距离规定的自动收货时间最近的订单。代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
$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队列中去,而且还是队列的顶端。以便下次获取。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
$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队列就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持快网idc。
相关文章
- 64M VPS建站:是否适合初学者操作和管理? 2025-06-10
- ASP.NET自助建站系统中的用户注册和登录功能定制方法 2025-06-10
- ASP.NET自助建站系统的域名绑定与解析教程 2025-06-10
- 个人服务器网站搭建:如何选择合适的服务器提供商? 2025-06-10
- ASP.NET自助建站系统中如何实现多语言支持? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-05-25 27
-
2025-05-27 84
-
2025-06-04 40
-
2025-06-05 27
-
2025-05-25 27