溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何在PHP中實現(xiàn)一個訂單自動確認(rèn)收貨的redis隊列

發(fā)布時間:2020-12-14 15:45:55 來源:億速云 閱讀:176 作者:Leah 欄目:開發(fā)技術(shù)

本篇文章為大家展示了如何在PHP中實現(xiàn)一個訂單自動確認(rèn)收貨的redis隊列,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

一、場景

之前做的電商平臺,用戶在收到貨之后,大部分都不會主動的點擊確認(rèn)收貨,導(dǎo)致給商家結(jié)款的時候,商家各種投訴,于是就根據(jù)需求,要做一個訂單在發(fā)貨之后的x天自動確認(rèn)收貨。所謂的訂單自動確認(rèn)收貨,就是在在特定的時間,執(zhí)行一條update語句,改變訂單的狀態(tài)。

二、思路

最笨重的做法,通過linux后臺定時任務(wù),查詢符合條件的訂單,然后update。最理想情況下,如果每分鐘都有需要update的訂單,這種方式也還行。奈何平臺太小,以及賣家發(fā)貨時間大部分也是密集的,不會分散在24小時的每分鐘。那么,定時任務(wù)的話,查詢過多,不適合。這里可以先把將要自動確認(rèn)收貨的訂單信息存儲到其他介質(zhì)上,比如redis,memcache,rabbitmq,然后執(zhí)行的腳本從前面的介質(zhì)獲取到訂單信息來判斷,這里可以大大的減少數(shù)據(jù)庫的查詢壓力。

redis隊列的生產(chǎn)者

對此,我們選擇每天在凌晨兩點的時候,通過linux的定時任務(wù)把即將要確認(rèn)收貨的訂單信息查詢出來,然后存儲在redis上,redis上我們選擇的隊列,隊列處理的特點就是先進(jìn)先出,前面的數(shù)據(jù)在查詢訂單時,通過發(fā)貨時間排序,所以最先出隊列的肯定是距離規(guī)定的自動收貨時間最近的訂單。代碼如下

$successCount=0;
$failCount=0;
$screen_time = 3600*24*9;//設(shè)置篩選天數(shù)
$data = array();
$now_time = time();
//查詢符合要求的數(shù)據(jù)
$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);
//當(dāng)隊列還有數(shù)據(jù)時將數(shù)據(jù)記錄并清除
while($redis->LLEN('auto_recevice_order')){
$txt = '執(zhí)行時間:'.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++;
}
//重新填充數(shù)據(jù)進(jìn)隊列
while ($row = $res->fetch_assoc()) {
 $successCount++;
 $redis->LPUSH('auto_recevice_order',json_encode($row1));
}
 $con->close();
 $success=date('Y-m-d H:i:s').':[推送成功]:本次成功推送數(shù)據(jù):'.$successCount.'條;記錄上次處理失敗數(shù)據(jù):'.$failCount."條\r\n";
 file_put_contents('./success_log.txt',$success."\r\n".PHP_EOL,FILE_APPEND);

redis隊列的消費(fèi)者

隊列的消費(fèi)者沒有通過linux的定時任務(wù)去做,用linux的screen+php cli模式執(zhí)行php腳本,消費(fèi)者只需要不斷的從隊列中讀取訂單信息,然后判斷訂單信息中的發(fā)貨時間,如果達(dá)到自動收貨的要求,就執(zhí)行update語句。同時如果沒有達(dá)到收貨的時間,而且與收貨時間間距比較大的時候,可以讓php腳本休眠sleep一定的時間數(shù),這個時間數(shù)自己調(diào)節(jié)設(shè)計,獲取出來的未達(dá)到時間要求的訂單,需要重新推送到redis隊列中去,而且還是隊列的頂端。以便下次獲取。代碼如下:

$set_time = 3600*24*10;//設(shè)置幾天后自動收貨
while(true){
if($i%30==0){
usleep(10);//防止while 循環(huán)使CPU使用率過高
}
if($redis->LLEN('auto_recevice_order')){
$data = json_decode($redis->RPOP('auto_recevice_order'));
$id = (int)$data->id;//將數(shù)據(jù)轉(zhuǎn)化為整形
$deliver_time = (int)$data->deliver_time;//將數(shù)據(jù)轉(zhuǎn)化為整形
$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);//更新數(shù)據(jù)
$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,'系統(tǒng)自動收貨','$ip','系統(tǒng)','服務(wù)器','收貨',$now_time)";//寫入訂單日志
 $res2 = $con->query($sql2);//添加日志數(shù)據(jù)
 }
 }
 if($res1==false){//將沒達(dá)到條件的數(shù)據(jù)重新插入隊列中
  $redis->RPUSH('auto_recevice_order',json_encode(array('id'=>$id,'deliver_time'=>$deliver_time)));
 }
}
 $i++;
}

這里執(zhí)行php腳本,需要用到linux的screen或者supervisor、nohup守護(hù)進(jìn)程。具體用法可自行百度.同樣腳本里面最好有必須的日志記錄。

三、思考

隨著業(yè)務(wù)的增長,在隊列中同一秒內(nèi),存在的多個需要處理的訂單,而一次只能從隊列中取出一個相關(guān)訂單信息的時候,可以采用一個生產(chǎn)者多個消費(fèi)者的模式,這種情況下,可以用到鎖機(jī)制,保證一條消息只能到達(dá)一個消費(fèi)者。當(dāng)redis數(shù)據(jù)達(dá)到一定的量之后,也可以適當(dāng)?shù)恼{(diào)整生產(chǎn)者的執(zhí)行頻率和對應(yīng)的條件。

上述內(nèi)容就是如何在PHP中實現(xiàn)一個訂單自動確認(rèn)收貨的redis隊列,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI