首頁  >  文章  >  後端開發  >  詳解PHP使用redis隊列實現電商訂單自動確認收貨

詳解PHP使用redis隊列實現電商訂單自動確認收貨

*文
*文原創
2018-01-03 11:54:422199瀏覽

PHP如何實現電商訂單自動確認收貨?今天小編就為大家帶來PHP使用redis隊列實現電商訂單自動確認收貨的知識。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望對大家有幫助。

一、場景

之前做的電商平台,用戶收到貨之後,大部分都不會主動的點擊確認收貨,導致給商家結帳的時候,商家各種投訴,於是就根據需求,要做一個訂單在發貨之後的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(&#39;auto_recevice_order&#39;)){
$txt = &#39;执行时间:&#39;.date(&#39;Y-m-d H:i:s&#39;).&#39;,信息:&#39;.$redis->RPOP(&#39;auto_recevice_order&#39;);
file_put_contents(&#39;./autoToken/fail_log.txt&#39;,$txt."\r\n".PHP_EOL,FILE_APPEND);
$failCount++;
}
//重新填充数据进队列
while ($row = $res->fetch_assoc()) {
 $successCount++;
 $redis->LPUSH(&#39;auto_recevice_order&#39;,json_encode($row1));
}
 $con->close();
 $success=date(&#39;Y-m-d H:i:s&#39;).&#39;:[推送成功]:本次成功推送数据:&#39;.$successCount.&#39;条;记录上次处理失败数据:&#39;.$failCount."条\r\n";
 file_put_contents(&#39;./success_log.txt&#39;,$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(&#39;auto_recevice_order&#39;)){
$data = json_decode($redis->RPOP(&#39;auto_recevice_order&#39;));
$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`=&#39;1&#39;,`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,&#39;系统自动收货&#39;,&#39;$ip&#39;,&#39;系统&#39;,&#39;服务器&#39;,&#39;收货&#39;,$now_time)";//写入订单日志
 $res2 = $con->query($sql2);//添加日志数据
 }
 }
 if($res1==false){//将没达到条件的数据重新插入队列中
  $redis->RPUSH(&#39;auto_recevice_order&#39;,json_encode(array(&#39;id&#39;=>$id,&#39;deliver_time&#39;=>$deliver_time)));
 }
}
 $i++;
}

這裡執行php腳本,需要用到linux的screen或supervisor、nohup守護程式。具體用法可自行百度.同樣腳本裡面最好有必須的日誌記錄。

三、思考

隨著業務的成長,在佇列中同一秒鐘內,存在的多個需要處理的訂單,而一次只能從隊列中取出一個相關訂單資訊的時候,可以採用一個生產者多個消費者的模式,這種情況下,可以用到鎖機制,保證一則訊息只能到達一個消費者。當redis資料達到一定的量之後,也可以適當的調整生產者的執行頻率和對應的條件。

相關推薦:

詳解php7如何實作MongoDB模糊查詢

# #####詳解PHP如何實作簡易的搜尋框自動提示功能###################php腳本中的$argv與$argc設定方法##### ####

以上是詳解PHP使用redis隊列實現電商訂單自動確認收貨的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn