公衆號重複推送消息的Bug

正常邏輯:在關注公衆號後,用關注時間+延後時間來進行定時任務執行推送,在特定的時間段推送特定的消息給微信用戶,每個access token的用戶同一條消息只會接收到一次。

Bug表象:有一部分微信用戶接到了重複的消息推送,比如關注後2小時的推送任務是“你好”,連續收到多條“你好”。造成了極大的用戶不良體驗,但是QA同學和自測試環境怎麼都無法復現這個Bug,無從下手排查。

使用技術:Node.js的egg.js框架 + Linux的CronTab定時器任務 + Mysql數據庫 + 微信公衆號開發工具
排查原因:

在執行發送任務時將文案等數據拼裝好交由微信那邊的接口發送到用戶的微信,再獲取哪些定時任務需要執行時候,是30秒輪詢一次看執行時間execute_time是否到了,到了的話就拿出來放入隊列中等待執行,執行完畢再修改數據庫定時任務狀態爲已執行。
(1)由於node是單線程,在用戶量到三四萬這個瓶頸的時候,就會容易出現這個Bug,因爲它單線程執行,30秒要推那麼多條消息顯然是不可能的,於是30秒還沒推送完全部,下一次30秒輪詢又到了,又把沒執行的定時任務拿出來轉圈圈等待發送,於是同一個用戶的同一個定時任務推送越堆積越多,導致最後推送N條重複的。
(2)我們進行的不是簡單的推送,還要查訂單,查課程信息,查老師聯繫方式,查優化方案,查上課時間,查…一堆一堆的數據拼接成的動態文案素材,在單線程環境下,雖然做了async , await 異步處理,但是主線程還是要根據子IO線程返回值拼接,所以非常佔用時間。
(3)在調用微信公衆號接口的時候,如果在30秒內微信用戶那邊沒有接收到消息的響應(網絡原因或者飛行模式或者在山上海里之類的),微信的接口會在30秒後進行重試機制,也就是再推一次,一共重試三次。

解決方案:

(1)延長輪詢時間,將原來的30秒改爲了三分鐘,但是這個很明顯治標不治本,用戶量再多的話也是執行不完。
(2)新增數據庫執行狀態爲“正在執行中”,一拿出該條用戶推送任務後就馬上修改狀態,而不是等推送完再修改,拿的時候不再拿這個狀態的定時任務。
(3)優化我們這邊獲取複雜數據的邏輯,優化SQL,將調用微信接口發送的那一步操作任務改爲異步執行,不加await回調,反正也不需要它的什麼返回值。

總結:

這個Bug開發環境是很難測試出來的,在生產環境確真實存在的。這個情況下我們就要考慮所使用的技術在高併發環境下是否會發生一些奇妙的事情。同時不斷提高自己的代碼質量,保證修改容易,排查問題容易。不要自己坑了自己。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章