欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

微信退费出现超时的处理

程序员文章站 2024-02-12 12:19:40
...

最近一家客户频繁反映,患者退费总是失败,导致意见比较大。于是我特意去查看了错误日志,退费出现连接超时,一天总共就四笔退费,每笔都出了问题。之前其他客户偶尔也有反馈,查看日志发现与当时的网络出现中断有很大关系,但这次只要退费就失败肯定是有问题的。

既然是超时了,优先考虑是不是超时时间设置太短了。查了下代码,用的第三方库,退费超时时间用的缺省值10秒,想想也不是很短,微信支付平台肯定不会需要这么长时间才能处理一笔业务,要不然就没法用了,于是就没从这里着手。

先是怀疑现场网络有问题,也写了个批处理,不停ping腾讯的服务器并打印日志。代码如下:

@echo off 
:loop  
ping -n 3 api.mch.weixin.qq.com >>d:\ping.log  
echo %date%-%time%>>d:\ping.log
timeout /T 3
goto loop 

每隔五秒,发起3次ping操作,打印到日志中然后停2秒。结果发现并没有出现网络中断的情况,想想也是,哪里那么凑巧,退费时网络就挂了,其他时间正常?

后台服务程序的错误日志打印出了以下堆栈:System.Net.WebException: The operation has timed out
   at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
   at System.Net.HttpWebRequest.GetRequestStream()  ......  拷贝出来先百度,倒是有人针对这个超时的问题做了比较详细的分析,给出了解决方案,例如keepalive要设置成false,增加System.Net.ServicePointManager.DefaultConnectionLimit = 200;增加System.GC.Collect();等等,挨个试了一下,换到现场去,当时能用,过段时间又挂了。还试过把证书重新导入了一下,也是当时成功,后来又不行。

既然每次都超时,那我写个winform的程序测试一下吧。放到现场,这个程序也失败,报连接超时。想着之前在哪里看到过,说调用腾讯平台的api最好使用腾讯云的DNS,不管对不对,先试试。换DNS后,居然测试程序不超时了。难道这是真相?心里也不信,付款的api是同一个域名,就从来没出过超时的问题,DNS解析还管你是不是退费?让同事测试一笔退费,说好了,那先暂且用着,估计还是要出问题的,果然下午又打电话来说退费又不能用。

我赶紧远程过去看,果然日志中又打出了超时的错误,再试试winform程序,居然连接正常。好吧,至少排除了一点,不是由于网络环境导致的问题,至少没有防火墙设置了规则进行拦截。之前我针对付款成功,退款失败的现象有过分析,二者使用的域名相同,但是退款需要使用双向证书,是不是有防火墙拦截了?于是我又回过头来考虑了一下,难不成真的就是超时了?假设一笔退款交易真的要10秒以上,那为什么其他客户不出问题?暂时也没有其他思路,先改一下超时时间的设置吧。

由于业务代码正在增加其他功能,不想恢复一个之前的版本进行修改,就改一下那个开源的第三方库。它的退款函数有一个参数是超时时间的设置,有缺省值10秒,我在调用时并没有传递这个参数。于是我就改了一下这个缺省值变为30秒,编译后放到现场。其实这个地方是有问题的,后面再说。

换了dll后,当时测试是成功的,后来又失败了。我不打算把30秒再改大,如果需要1分钟退一笔款,那还不全网吐槽,我还真没百度到这样的网页。感觉范围越来越小,只能瞄准IIS。于是我又做了一个测试网站,点击按钮发起一次无效退款,看是否超时。还真测试出来一些问题,重启应用程序池后会大概率出现超时,回收应用程序池后,也有一定几率造成超时;点击后在10秒内做10次无效退款,结果只有第一次失败,而且后面9次很快,基本在几百毫秒内完成。看来在没有缓存的情况下,这个双向证书的通信初始化确实要花很多时间。那么是不是由于这个初始化时间太长导致的网络超时呢?是不是要打印个日志出来看看?于是再改了下代码,加了时间消耗打印,不停重启应用程序池,果然有时候要超过10秒,最长的时候是17秒。不对啊,我不是改过超时时间是30秒么?拿那个改过的dll来试试,10秒之后就超时了。这是什么情况?

这就是我前面说到的问题。如果我们有一个第三方库,里面有个函数,例如

public int add(int i1,int i2=2)
{
    return i1 + i2;
}

调用的时候是这么写的,int i = add(1);编译好后测试,i = 3  但是如果我们只改第三方库函数的缺省值,改成i2=3,并且只编译第三方库后换回去,测试会得到 i=4 么?答案是不会。原因是编译 int i= add(1);的时候,虽然我们只写了一个参数,但是编译器会自动把另外一个参数自动加上去,用的数值是编译时第三方库函数参数的缺省值。所以后来即使改了第三方库的缺省值,但是调用方没有重新编译,那么还是用的之前的缺省值。

我以为自己把超时时间改到了30秒,其实啥也没干。赶紧再改改第三方库,直接在函数体内设置超时时间。换到测试网站里面,再怎么停止和回收应用程序池,都不会超时。

看来是简单问题复杂化了,另外还有一个疑问,为什么我之前采用的方式都能短时间治标,一会又over呢?原来IIS的应用程序池有一个设置,默认情况下只要20分钟没有人访问网页,就会自动将进程回收。我用的那些治标方式,其实都是失败一次后,刚好还有缓存没回收,于是看上去解决问题了。等到了晚上或者中午,没有业务发生时,进程被自动回收,自然又会出问题。

相关标签: 微信相关开发