您的位置:首页 > 其它

一个小BUG的解决过程。

2014-07-21 17:50 253 查看
我们的系统中有一个组件是接收从服务器推送过来的用户在线状态的通知消息并通知给自己的客户端UCService。这个组件以JAR包形式提供给UCService。此为背景。

一天测试人员报告说总是突然发生所有的通知消息都收不到了。以下是追查过程:

1 检查日志,发现我们的组件确实收到了服务器推送过来的消息。

2 没发现组件向UCService推送消息的日志。当然代码里有推送相关的日志。

3 检查组件这部分的代码。代码收到服务器的消息,会把消息放到一个队列里,由另一个线程负责从队列里取消息并发送给UCService。那可能的错误点有两个:或者是写队列的代码有BUG,或者取队列的代码有BUG。

4 根据现象描述,出故障之后,所以的新消息都无法推送,那明显是某个线程退出了。既然一直都有收到消息的日志,那一定是从队列里取消息并发送的线程不存在了。

5 检查这部分的代码。代码如下:

1 public void run() {

2 while (true) {

3 try {

4 OnPresenceChangedSubInfo info = queue.take();

5 if (info != null) {

6 PresenceInfo presenceInfo = info.getPresenceInfo();

7 List<String> subscriberUserList = info

8 .getSubscriberUserList();

9 listener.onPresenceChanged(presenceInfo, subscriberUserList);

10 }

11 } catch (InterruptedException e) {

12 e.printStackTrace();

13 }

14 }

15 }

肯定是循环体里的代码抛出没有被捕捉的异常了。那为什么没被捕获呢?问题找到了。这里只捕获了InterruptedException,而对其它可能发生的异常并没有捕获。而第9行里调用了一个由UCService实现的回调方法,这个方法很有可能抛出RuntimeException或者其它的Throwable。到底可能是哪种错误需要捕捉呢?需要好好分析它的代码... ...

6 我的答案是:不需要!这个线程不需要处理UCService的错误,我们要做的只是容错,也就是捕获异常并记录它。把第11-12行代码改为:

11 } catch (Throwable e) {

12 logger.writeError(e);

7 修改代码并重新部署后,故障消失。

BUG点评:

这是一个典型的对异常处理不当的BUG。我们的目标是保证线程绝不会异常退出,那只捕获非RuntimeException只能保证你的代码编译通过,而不能保证它能正常运行。

而有BUG的代码尤其错误的是,它在捕获异常后仅仅是把它打印在标准错误输出上,而这非常容易造成错误信息丢失。这种处理方式纯粹是把HelloWorld里的编程水平带到工作中来了。

关于JAVA的异常处理,可以写成好几本书。对于本文中提到的场景,我们只关心线程是否能正常运行,对异常的处理要求并不高,不需要按照异常的各类进行个性化的处理。所以直接捕获Throwable就好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bug 异常处理 故障