IDC

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

作者:admin 2021-04-11 我要评论

本文转载自微信公众号「UP技术控」,作者conan5566。转载本文请联系UP技术控公众号。 背景 做微信公众号开发的时候,其中有个接收普通消息、接收事件推送 API。 ...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

 

本文转载自微信公众号「UP技术控」,作者conan5566。转载本文请联系UP技术控公众号。 

背景

做微信公众号开发的时候,其中有个接收普通消息、接收事件推送 API。

有这么条规则, ”微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。详情请见“发送消息-被动回复消息””。

概括起来就2点

1、就是说5s没响应,这个请求就会被放弃;

2、会重新发起请求,具有幂等性;

问题

这样就会产生2个问题。

1、假设我的方法就正好需要6s,那么即使返回结果也是没用的,因为请求被放弃了。

2、我需要返回给用户正确的回信,假设第一次超时没法及时回信,比如绑定操作,第一次没回信,第二次再来总不能回复绑定过了,这样显然不合理。

或者直接回复 success ,这样显然没法正常的进行消息提醒。

那么怎么做到既执行了操作(第一次超时了),(第二次微信重试)又及时回复正确的回信呢 。

代码实现

1、定义缓存的key,就是消息MsgId。

  1. string cacheKey = model.MsgId.ToString(); 

2、使用缓存机制,把结果缓存起来,下次进来,直接回复上次执行的结果。

  1. TimeSpan expired = new TimeSpan(0, 0, 20); 
  2.                     string cacheKey = model.MsgId.ToString(); 
  3.                     return _cacheLayer.Get(cacheKey, () => 
  4.                     { 
  5.                         MsgReply param = new MsgReply() { ToUserName = model.FromUserName, FromUserName = model.ToUserName }; 
  6.                         string Jsonstr = WeiXinHelper.ReadAccess(HttpRuntime.AppDomainAppPath.ToString() + "/App_Data/WeChat/KeyWordReplay.json"); 
  7.                         var r = JsonConvert.DeserializeObject<AutoReplay>(Jsonstr); 
  8.                         param.Content = r.content; 
  9.                         if (String.Equals(model.MsgType, "text", StringComparison.CurrentCultureIgnoreCase)) 
  10.                         { 
  11.                             var item = r.keywordcontent.FirstOrDefault(o => o.keyword.Contains(model.Content)); 
  12.                             if (item != null
  13.                             { 
  14.                                 param.Content = item.content; 
  15.                             } 
  16.                         } 
  17.  
  18.                         string response = _weChatAlertsService.SubscribeReply(param); 
  19.                         AddReceiveLog(model, xml, response); 
  20.                         return response; 
  21.                     }, expired); 

3、这样既解决幂等问题,也返回了正确的结果。

4、这里需要注意,缓存取得每个 Key专有的 lock object;若同时有多个 thread要求相同资料,只会(到数据库)查第一次,剩下的从 cache读取。

  1. public T Get<T>(string key, Func<T> getDataWork, TimeSpan absoluteExpireTime, bool forceRefresh = false, bool returnCopy = truewhere T : class 
  2.         { 
  3.             try 
  4.             { 
  5.                 lock (GetMemoryCacheLockObject(key)) 
  6.                 { 
  1. private static object GetMemoryCacheLockObject(string key
  2.         { 
  3.             string cacheLockKey = string.Format(MemoryCacheLockObjectFormat, key); 
  4.             lock (CacheObject) 
  5.             { 
  6.                 var lockObject = CacheObject[cacheLockKey]; 
  7.                 if (lockObject == null
  8.                 { 
  9.                     // 取得每個 Key專屬的 lock object;若同時有多個 thread要求相同資料,只會(到資料庫)查第一次,剩下的從 cache讀取 
  10.                     lockObject = new object(); 
  11.                     CacheObject.Set
  12.                         cacheLockKey, 
  13.                         lockObject, 
  14.                         new System.Runtime.Caching.CacheItemPolicy() 
  15.                         { 
  16.                             AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(10) 
  17.                         } 
  18.                     ); 
  19.                 } 
  20.  
  21.                 return lockObject; 
  22.             } 
  23.         } 

总结

1、使用缓存机制,把第一次的结果保存下来,对方重试的时候,直接返回上次的结果。

2、使用lock ,保证并发的时候,若同时有多个 thread要求相同资料,只会(到数据库)查第一次,剩下的从 cache读取。


本文转载自网络,原文链接:https://mp.weixin.qq.com/s/tuiOP4xl_ziYAWCErxHtgA

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 太棒了!Python和Excel过了这么久终于

    太棒了!Python和Excel过了这么久终于

  • Java编程内功-数据结构与算法「线索化

    Java编程内功-数据结构与算法「线索化

  • 在Java中使用异步编程

    在Java中使用异步编程

  • Kafka性能篇:为何Kafka这么&quot;

    Kafka性能篇:为何Kafka这么&quot;

腾讯云代理商
海外云服务器