天天看點

微信開發中的消息排重機制實作

微信公衆平台開發時,微信推送消息的機制是推送過來後如果5秒内收不到響應則認為沒有推送成功,會再次推送,總共推送三次。如果我們伺服器接收到消息沒有及時響應,就會觸發微信的“重推機制”,這就需要我們在服務端對微信推送過來的消息進行排重。

我們不應該讓伺服器出現處理時間過長的情況,對于業務複雜、處理時間長度不可控的代碼可以進行異步處理,每次接收到微信推送後都立即傳回空串,當然這是另外一回事了,不是今天要說的。

先看微信公衆号開發文檔原文

1、關于重試的消息排重,推薦使用msgid排重。 2、微信伺服器在五秒内收不到響應會斷掉連接配接,并且重新發起請求,總共重試三次。假如伺服器無法保證在五秒内處理并回複,可以直接回複空串,微信伺服器不會對此作任何處理,并且不會發起重試。
微信伺服器在五秒内收不到響應會斷掉連接配接,并且重新發起請求,總共重試三次

關于重試的消息排重,推薦使用FromUserName + CreateTime 排重。

假如伺服器無法保證在五秒内處理并回複,可以直接回複空串,微信伺服器不會對此作任何處理,并且不會發起重試。

微信推送過來的消息無外乎上面兩種,微信文檔也給出了排重方法,下面說說我的方案:

建立判斷重複消息的DuplicateRemovalMessage類;

把微信推送的消息解析指派給DuplicateRemovalMessage對象執行個體;

用靜态變量List當緩存,判斷DuplicateRemovalMessage執行個體是否存在于緩存list中,如果存在則為重複消息,如果不存在則不是重複消息并把消息放到緩存List中。

此方案弊端:

緩存list會無限增大,是以用setMessageToCache方法限制了list最大容量為1000;

解決了list最大容量依然還有弊端,就是兩條重複的消息之間如果有超過999個DuplicateRemovalMessage對象依然會判斷不準,隻能增大list容量來緩解。

實作代碼:

别忘記複寫hashcode、equals方法

方案一的解決并不優雅,而且無法在負載均衡環境下使用。

改進方式是在【方案一】的基礎上,使用redis替換List作為存儲中介,将DuplicateRemovalMessage對象存儲到redis中,存儲的key可以用msgId,事件消息可以用FromUserName + CreateTime 拼接,同時給對象設定一個15秒的逾時時間,這樣就不會有List那種集合存儲元素無限增多的情況。

微信推送消息的CreateTime 精确到秒值,這就可能出現一個使用者正常操作的情況下觸發兩條FromUserName 和CreateTime 完全相同的消息,也就是說按照微信文檔上提供的排重方法會過濾掉合法資料,我線上上環境遇到過一次。

我們微信公衆号開啟了擷取使用者地理位置的功能,使用者打開微信後點選菜單進入了某個頁面,此時微信背景向我們推送了使用者地理位置事件消息和使用者點選公衆号菜單事件消息,這兩個消息的CreateTime 和FromUserName 相同。

是以最後建議做排重的時候,事件消息使用FromUserName + CreateTime+Event三個字段進行排重。

本文最初釋出在iteye,由于iteye編輯部落格内容提示我有敏感詞,可是又不告訴我是哪個敏感詞(真2b),無法編輯老文章,是以文章和更新以後都發到這裡了。

(全文完)