记录一个比较2b的递归错误

业务场景:下载网络图片时可能出错,需要重试。与Retry相关。

其实关于重试,Spring本身就有Retry模块,我对于这个功能想的很简单,重试那就递归调用呗,如果调用结果出错就增加一个调用延迟,然后继续调用,直到超出调用次数本次请求彻底失败。

但是在测试的时候却发现逻辑上完全没有问题的代码结果却和预期结果大相径庭,我刻意让调用结果第一次失败第二次成功,而该方法返回的仍然是第一次失败的结果。这让我彻底傻了眼,先去自己查了一下资料,然后又寻求了一下帮助,发现自己犯了一个非常低级的错误。

这里先上有问题的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
private <T> SimpleResponse<T> downLoadImage(String url ,int times , boolean returnStream) {
SimpleResponse<T> response = new SimpleResponse<>();
response.setCode(SimpleResponse.SUCCESS);
if (times == 3) {
log.error("已达重试上限");
response.setCode(SimpleResponse.ERROR);
return response;
}
HttpURLConnection con;
ByteArrayOutputStream out;
byte[] image;
RobotProxy robotProxy = null;

try {
log.info("返回Byte[],第[{}]次下载,开始下载URL为:[{}]的图片", times, url);
URL urlObj = new URL(url);

robotProxy = proxyService.getProxy(url);

if (robotProxy != null) {
Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress(robotProxy.getIp(), robotProxy.getPort()));
con = (HttpURLConnection)urlObj.openConnection(proxy);
}else {
con = (HttpURLConnection)urlObj.openConnection();
}
InputStream in = con.getInputStream();
if (returnStream) {
response.setData((T)in);
}else {
out = new ByteArrayOutputStream();
int l;
byte[] buffer = new byte[10 * 1024];
while ((l = in.read(buffer)) != -1) {
out.write(buffer, 0, l);
}
image = out.toByteArray();
in.close();
out.flush();
out.close();
response.setData((T)image);
}
if (robotProxy != null && robotProxy.getErrorTimes() >0) {
robotProxy.setErrorTimes(0);
proxyService.updateById(robotProxy);
}
} catch (Exception e) {
log.error("下载图片失败,失败信息:[{}]", e.getClass().getName());
times++;
if (robotProxy != null) {
proxyService.updateProxyError(robotProxy,url);
}
// 重试
downLoadImage(url ,times ,returnStream);
}
return response;
}

不知道你是否能发现问题,其实问题在于重试的地方。

让我们看看Debug情况下第一次下载失败然后进行重试,第二次成功时的方法栈。

可以看到这里有2个方法栈,因为第一次调用失败后进行了重试。

第一次中包含了下载失败的异常信息

重试之后下载成功,返回。

但是返回的时候你会发现,第二次成功的返回值被丢掉了,最终返回的是第一个方法栈的返回值,也就是下载错误的值。

所以问题就在这行代码

downLoadImage(url ,times ,returnStream);

因为重试的时候没有把下次的调用结果赋值给response,导致就算成功了,return的也是第一次错误的值。

将代码修改一下

1
response= downLoadImage(url ,times ,returnStream);

问题解决。

以前写过的递归代码还是太少了,这个坑虽然显得有点傻,却给我上了印象深刻的一课。

分享到:
0%