背景
做微信公眾號開發的時候,其中有個接收普通訊息、接收事件推送 API,
有這么條規則, ”微信服務器在五秒內收不到回應會斷掉連接,并且重新發起請求,總共重試三次,假如服務器無法保證在五秒內處理并回復,可以直接回復空串,微信服務器不會對此作任何處理,并且不會發起重試,詳情請見“發送訊息-被動回復訊息””,
概括起來就2點
1、就是說5s沒回應,這個請求就會被放棄;
2、會重新發起請求,具有冪等性;
問題
這樣就會產生2個問題,
1、假設我的方法就正好需要6s,那么即使回傳結果也是沒用的,因為請求被放棄了,
2、我需要回傳給用戶正確的回信,假設第一次超時沒法及時回信,比如系結操作,第一次沒回信,第二次再來總不能回復系結過了,這樣顯然不合理,

或者直接回復 success ,這樣顯然沒法正常的進行訊息提醒,
那么怎么做到既執行了操作(第一次超時了),(第二次微信重試)又及時回復正確的回信呢 ,

代碼實作
1、定義快取的key,就是訊息MsgId,
string cacheKey = model.MsgId.ToString();
2、使用快取機制,把結果快取起來,下次進來,直接回復上次執行的結果,
TimeSpan expired = new TimeSpan(0, 0, 20); string cacheKey = model.MsgId.ToString(); return _cacheLayer.Get(cacheKey, () => { MsgReply param = new MsgReply() { ToUserName = model.FromUserName, FromUserName = model.ToUserName }; string Jsonstr = WeiXinHelper.ReadAccess(HttpRuntime.AppDomainAppPath.ToString() + "/App_Data/WeChat/KeyWordReplay.json"); var r = JsonConvert.DeserializeObject<AutoReplay>(Jsonstr); param.Content = r.content; if (String.Equals(model.MsgType, "text", StringComparison.CurrentCultureIgnoreCase)) { var item = r.keywordcontent.FirstOrDefault(o => o.keyword.Contains(model.Content)); if (item != null) { param.Content = item.content; } } string response = _weChatAlertsService.SubscribeReply(param); AddReceiveLog(model, xml, response); return response; }, expired);
3、這樣既解決冪等問題,也回傳了正確的結果,
4、這里需要注意,快取取得每個 Key專有的 lock object;若同時有多個 thread要求相同資料,只會(到資料庫)查第一次,剩下的從 cache讀取,
public T Get<T>(string key, Func<T> getDataWork, TimeSpan absoluteExpireTime, bool forceRefresh = false, bool returnCopy = true) where T : class { try { lock (GetMemoryCacheLockObject(key)) {
private static object GetMemoryCacheLockObject(string key) { string cacheLockKey = string.Format(MemoryCacheLockObjectFormat, key); lock (CacheObject) { var lockObject = CacheObject[cacheLockKey]; if (lockObject == null) { // 取得每個 Key專屬的 lock object;若同時有多個 thread要求相同資料,只會(到資料庫)查第一次,剩下的從 cache讀取 lockObject = new object(); CacheObject.Set( cacheLockKey, lockObject, new System.Runtime.Caching.CacheItemPolicy() { AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(10) } ); } return lockObject; } }
總結
1、使用快取機制,把第一次的結果保存下來,對方重試的時候,直接回傳上次的結果,
2、使用lock ,保證并發的時候,若同時有多個 thread要求相同資料,只會(到資料庫)查第一次,剩下的從 cache讀取,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/255791.html
標籤:.NET Core
