2021年2月2日星期二

使用缓存防击穿,解决微信”被动回复用户消息”重试回复问题

背景

 做微信公众号开发的时候,其中有个接收普通消息、接收事件推送 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, 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读取。









原文转载:http://www.shaoqun.com/a/522402.html

跨境电商:https://www.ikjzd.com/

宝付:https://www.ikjzd.com/w/539

文化衫事件:https://www.ikjzd.com/w/1932


背景做微信公众号开发的时候,其中有个接收普通消息、接收事件推送API。有这么条规则,"微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。详情请见"发送消息-被动回复消息""。概括起来就2点1、就是说5s没响应,这个请求就会被放弃;2、会重新发起请求,具有幂等性;问题这样就会
淘粉8:淘粉8
东杰智能:东杰智能
分析|亚马逊新手卖家如何选择站点和品类?:分析|亚马逊新手卖家如何选择站点和品类?
口述:玩笑恶搞让同性恋老公浮出水面(2/2):口述:玩笑恶搞让同性恋老公浮出水面(2/2)
口述:小姑子和我抢老公 只穿内裤在屋里晃:口述:小姑子和我抢老公 只穿内裤在屋里晃

没有评论:

发表评论