之前做的電商平臺,用戶在收到貨之后,大部分都不會主動的點擊確認收貨,導致給商家結(jié)款的時候,商家各種投訴,于是就根據(jù)需求,要做一個訂單在發(fā)貨之后的x天自動確認收貨。所謂的訂單自動確認收貨,就是在在特定的時間,執(zhí)行一條update語句,改變訂單的狀態(tài)。
成都創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設,彭澤企業(yè)網(wǎng)站建設,彭澤品牌網(wǎng)站建設,網(wǎng)站定制,彭澤網(wǎng)站建設報價,網(wǎng)絡營銷,網(wǎng)絡優(yōu)化,彭澤網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。最笨重的做法,通過linux后臺定時任務,查詢符合條件的訂單,然后update。最理想情況下,如果每分鐘都有需要update的訂單,這種方式也還行。奈何平臺太小,以及賣家發(fā)貨時間大部分也是密集的,不會分散在24小時的每分鐘。那么,定時任務的話,查詢過多,不適合。這里可以先把將要自動確認收貨的訂單信息存儲到其他介質(zhì)上,比如redis,memcache,rabbitmq,然后執(zhí)行的腳本從前面的介質(zhì)獲取到訂單信息來判斷,這里可以大大的減少數(shù)據(jù)庫的查詢壓力。
對此,我們選擇每天在凌晨兩點的時候,通過linux的定時任務把即將要確認收貨的訂單信息查詢出來,然后存儲在redis上,redis上我們選擇的隊列,隊列處理的特點就是先進先出,前面的數(shù)據(jù)在查詢訂單時,通過發(fā)貨時間排序,所以最先出隊列的肯定是距離規(guī)定的自動收貨時間最近的訂單。代碼如下
$successCount=0; $failCount=0; $screen_time?=?3600*24*9;//設置篩選天數(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); //當隊列還有數(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ù)進隊列 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);隊列的消費者沒有通過linux的定時任務去做,用linux的screen+php cli模式執(zhí)行php腳本,消費者只需要不斷的從隊列中讀取訂單信息,然后判斷訂單信息中的發(fā)貨時間,如果達到自動收貨的要求,就執(zhí)行update語句。同時如果沒有達到收貨的時間,而且與收貨時間間距比較大的時候,可以讓php腳本休眠sleep一定的時間數(shù),這個時間數(shù)自己調(diào)節(jié)設計,獲取出來的未達到時間要求的訂單,需要重新推送到redis隊列中去,而且還是隊列的頂端。以便下次獲取。代碼如下:
$set_time?=?3600*24*10;//設置幾天后自動收貨 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)','服務器','收貨',$now_time)";//寫入訂單日志 ?$res2?=?$con->query($sql2);//添加日志數(shù)據(jù) ???} ?} ?if($res1==false){//將沒達到條件的數(shù)據(jù)重新插入隊列中 ?????$redis->RPUSH('auto_recevice_order',json_encode(array('id'=>$id,'deliver_time'=>$deliver_time))); ???} } ?$i++; }這里執(zhí)行php腳本,需要用到linux的screen或者supervisor、nohup守護進程。具體用法可自行百度.同樣腳本里面最好有必須的日志記錄。
隨著業(yè)務的增長,在隊列中同一秒內(nèi),存在的多個需要處理的訂單,而一次只能從隊列中取出一個相關訂單信息的時候,可以采用一個生產(chǎn)者多個消費者的模式,這種情況下,可以用到鎖機制,保證一條消息只能到達一個消費者。當redis數(shù)據(jù)達到一定的量之后,也可以適當?shù)恼{(diào)整生產(chǎn)者的執(zhí)行頻率和對應的條件。
另外有需要云服務器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。