Ruby 异常处理

liuxingqi bio photo By liuxingqi Comment

考虑异常

今天我被程序中的异常所困扰,至今我才发现我对ruby的异常处理机制了解的太少,而且没有意识到在什么情况下应该处理异常。在我工作的项目中,存在着各种各样的问题,例如存在一张没有唯一性约束的表,合服过 程中导致ID重复,我尝试编写脚本去处理重复ID,我认为我考虑到了一切出错的可能性,但是运维在部署的过程中出现了错误,导致整个部署失败。运维的同事告诉我:为什么连基本的异常处理都没有? 这件事情让我相当懊恼,我以为我考虑到了所有情况,但还是出错了,我的脑子里一直在抱怨这垃圾的项目,为什么会出现如此多的问题,我的工作只是在不断的擦屁股,救火…..但我心里清楚,我的代码不够健壮,这是我的错! 接着我给代码添加了异常处理,一切问题解决了….

经过这件事情,我给了自己一些提醒:

  1. 如果你维护的系统代码质量太差,不要信任任何它提供的东西,说不定在某个地方就潜藏着危险,如果你中招,你将会为别人的错误买单;

  2. 如果你的代码有if语句,请一定要考虑else的情况。试着想一下,如果没有else语句,程序是否健壮,是否会出错;

  3. 如果你的心里在想:“这段代码一定(应该)不会出错!” 那么建议你实际运行一下这段代码,如果带有参数,请考虑特殊值;

  4. 需要想一下:“如果运行这段代码出现异常,会有什么样的后果?会导致部署失败么?用户会无法登陆么?玩家的操作会受影响么?会影响项目收入么?会花费很大的代价去修复么?还是会被鄙视么?…..” 如果你的答案是确定的,建议添加上异常处理。

捕获异常

我把项目中关于异常处理相关的代码全部浏览了一遍,发现无论是我还是我的同事,对于异常的处理都非常简单。

begin
    #some code
    raise "some info"
rescue => e
    #some code
end

如果你主动的抛出异常信息,rescue从句捕获的是RuntimeError。

begin
    #some code
rescue => e
# equal to StandardError => e
    #some code
end

这个rescue从句只处理属于StandardError(及其子类),会忽略其他异常,如果你不了解ruby的异常类,可以看看下图:

ruby异常类的继承结构

同时也存在这样一种异常处理方式:

begin
    #some code
rescue Exception => e
    #some code
end

这个rescue从句会捕获所有的异常。但这不是一个明智的做法,而且是个很坏的主意。

ruby异常处理的风险

不要试图去捕获所有的异常,你所捕获的异常最好是StandardError(及其子类),因为这些异常是比较“普通”的异常,而其他的异常属于更底层,更严重的异常,一般的ruby程序是不会去处理这些异常,而如果你捕获了这些异常又没有做相应的处理,可能会引起意想不到的情况发生。例如,如果你捕获了SignalException,会导致你的程序无法正常退出,成为僵尸进程或线程。

处理异常

如果你捕获了程序的异常,但是却不对它做任何处理,虽然它让你的程序不会崩溃或中断,但是你并没有利用到这些异常信息的价值,尤其是对那些你意想不到的异常情况。 在我工作的项目中,日志系统要求对玩家的资源做出精准的记录,如果任一玩家的资源记录不准确,将会引发报警,我必须快速修复。在日志系统上线之后,隔三差五的总是会有报警信息,我尝试去找出原因,却发现没有任何信息让我跟踪,因为我捕获的异常信息被丢进了log目录中的某个文件,而这个log目录下的文件会每隔两个小时清理一次… 所以如果你捕获到异常,一定要对它进行处理,无论是发送包含异常信息的邮件给你,还是将异常信息放在单独的不会被清理的log中,这样会方便你追踪,省下大量的时间。

rails的异常处理

rails的异常处理

comments powered by Disqus