大约有一年整没有写一篇博客了,由于各种原(jia)因(ban)导致闲暇时间要么拿着IPad看岛国奇怪的片(dong)子(hua)、要么拿着kindle看各种各样的资(xiao)料(shuo)。本来想写的一个介绍MEF的专题也果断在完成50%后砍掉,结果这两天想准备点关于IOC(不是国际奥委会那个IOC)的内部材料,发现之前准备的一些资料也已经顺手删掉了,可惜可惜。

不说别的了,就说这两天自己给自己挖的一个坑。说起来还挺有趣的,原因不复杂,就是最基本的知识点,只是手头的模块略复杂,一开始还真没猜到自己是栽在这坑里。

一个BUG,一个关于IDisposable的故事

事情是这样的,前天下午同事屁颠屁颠跑过来,吼道:“报错啦,报错啦,天塌啦,地陷啦”,嗯,差不多他就是这个意思。

当然,他吼了什么一点都不重要,重要的是一番检查后确认是系统其他地方存在问题,这里抛出异常是合情的合理的合法的美帝大统领看到了也要喊YES WE CAN THROW独国默大妈瞧见了双手摊开轻身细语我要让世界知道这个异常是要抛的股神巴菲特听到了抛字一路比划着一路小跑而来请原谅我忘记了标点的用法因为标点已经阻碍了我表达对这个异常被抛出的正确性的认知。

通常来说,剧情发展到一半的时候,如果前期BOSS被干掉了,就意味着后面还要出现一个幕后黑手——要不然这戏份怎么凑啊编剧?这几年国产片各种捞票作,各种侮辱观众的智商的片子也没这么拍的嘛。

是的,同样的代码,同样的参数调用,第二次这异常就神奇的消失了……在确认天上没有Blink Blink小圆盘地下没有Pink Pink小圆神后,反复重试都是第一次抛异常,后面就默默的什么都没有了。由于代码层次较多,相关数据也很多,在代码战争的汪洋大海中一番折腾后总算找出了一番的BUG(差不多下面的意思):

class Foo : IDisposable
{
DbContext ctx;
...
public void Dispose()
{
ctx.SaveChanges(); //Fuck my life
... //其他资源释放
}
}

原先在设计Foo类的时候,希望调用者能在完成一系列的操作后整体保存修改到数据库中,如果报错则在新的Foo实例中重试(以防止EF的缓存导致数据污染)。由于EF将在SaveChanges时将内存中的修改放在一个事务中统一提交,也为了方便调用者使用此类,故而考虑了在Dispose()中调用SaveChanges()的做法。于是调用者可以采用如下轻松又愉悦的姿势调用:

using(var foo = new Foo())
{
...
}

到此,各位看官看出问题来了么?这个低级的错误刚看到时一时半会还真没想出来:

  1. using语句块相当于try...finally的简化写法,保证了实现IDisposable的资源在离开语句块时Dispose()方法会被执行。
  2. 由于处理过程中的异常没有被catch,故而异常被沿着调用堆栈逐级向上抛出——这不是重点,重点是程序离开了using语句块,所以Dispose()方法被!调!用!了!,Dispose()方法被!调!用!了!
  3. Dispose()方法被!调!用!了!因为很重要所以要说三遍,本条凑数用。
  4. 由于在异常抛出前,已经有部分实体的状态被修改,故而惨遭提交。Q.E.D.

还好本模块实现了事件溯源,高大上点的说法叫Event Sourcing。最终是发现在异常抛出后事件记录多了几条,才意识到这个坑爹的问题的。看来引入Event Sourcing的概念,虽然目前还没有发挥多少价值,就冲帮我找到了这个BUG上(如果直接查看数据,那真得疯掉了),值了。

发现问题,解决倒也简单。加个标记位简单记录下是否处理过程发生异常即可。正如张〇忌般,历经世事后迎来了回老家画眉(不愧是明教教主,就是躲过了回老家结婚的flag)的平淡结局。

标题NETA了希区柯克的《捉贼记》(To Catch a Thief),当然片子我还没看。

捉BUG记(To Catch a Bug)的更多相关文章

  1. 解Bug之路-串包Bug

    解Bug之路-串包Bug 笔者很热衷于解决Bug,同时比较擅长(网络/协议)部分,所以经常被唤去解决一些网络IO方面的Bug.现在就挑一个案例出来,写出分析思路,以飨读者,希望读者在以后的工作中能够少 ...

  2. 捉虫记(四)线程安全导致的HighCpu

    一个朋友QQ群里说网站启动后会cpu很高,想要帮忙看一下dump. 1.打开windbg加载dump文件后第一个命令lmf,这个命令显示加载的dll以及路径,这样子可以找个dll来帮忙加载sos,(额 ...

  3. ie7,8常见bug,共计257个bug汇总?如何解决ie的历史bug

    ie7.8常见bug,共计257个bug汇总 针对web开发者来说,浏览器的bug,特备是ie的bug是很多人的噩梦,因为ie的更新换代没有ff,chrome,safari,opera那么快,而且ie ...

  4. 软件测试中Bug的生命周期以及Bug的严重等级

    软件测试中Bug的生命周期以及Bug的严重等级 我猜你们都会,但能说专业且全面不? 1.首先当测试人员接到一个项目或产品准备测试的时候,测试人员会根据测试用例一步步的来执行用例进行简单的功能测试.当测 ...

  5. DK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。

    NIO的epoll空轮询bug - Lost blog - 博客园 https://www.cnblogs.com/JAYIT/p/8241634.html NIO的epoll空轮询bug   JDK ...

  6. 软件测试过程中如何区分什么是功能bug,什么是需求bug,什么是设计bug?

    问题描述: 测试过程中如何区分什么是功能bug,什么是需求bug,什么是设计bug? 精彩答案: 会员 土土的豆豆: 本期问题其实主要是针对不同方面或纬度上对于bug的一个归类和定位. 个人认为,从软 ...

  7. 记一次偶发的bug排查——redis-py-cluster库的bug

     排查流水账: 通过平台监控,发现很多偶发的查看推荐列表的接口时延大于0.5s 写单元测试,不能重现.在测试环境不能重现.只有在正式环境可以偶发重现. 通过日志埋点,等待重现 不断地加日志埋点后发现耗 ...

  8. 记一次令人发狂的 bug Eclipse 开不开 tomcat 7.0

    改项目,结果发现以前的项目也出了问题,就删除了系统用户下面workplace里的文件夹,结果,eclipse被清空,重新添加项目,发现一堆bug; 最让我崩溃的是,用tomcat 7.0跑项目,反复出 ...

  9. 记一个神奇的Bug

    多年以后,当Abraham凝视着一行行新时代的代码在屏幕上川流不息的时候,他会想起2019年4月17日那个不平凡夜晚,以及在那个夜晚他发现的那个不可思议的Bug. 虽然像无数个普普通通的夜晚一样,我在 ...

随机推荐

  1. PHP中使用Session配合Javascript实现文件上传进度条功能

    Web应用中常需要提供文件上传的功能.典型的场景包括用户头像上传.相册图片上传等.当需要上传的文件比较大的时候,提供一个显示上传进度的进度条就很有必要了. 在PHP .4以前,实现这样的进度条并不容易 ...

  2. dispay属性的block,inline,inline-block

    转自下面的几位大神: http://www.cnblogs.com/KeithWang/p/3139517.html 总体概念 block和inline这两个概念是简略的说法,完整确切的说应该是 bl ...

  3. TJI读书笔记09-访问控制权限

    TJI读书笔记09-访问控制权限 包,package和import 权限修饰符 接口和实现 类的访问权限控制 首先问一个问题,为什么要有访问控制权限? 安全,这当然是一个很重要的原因. 让类库的使用者 ...

  4. C#去掉list集合中的重复数据

    List<string> conList= new List<string>(); List<string> listII = new List<string ...

  5. ORACLE 10进制与16进制的互相转换

    1. 10---->16 使用to_char(10,'xxx')函数,如果位数长,多加几个 x 2. 16---->10 使用to_number(’a','xxx')函数,如果位数长,多加 ...

  6. PLAN表

    用得较多的PLAN表有以下三个ABPPMGR:MANUFACTURINGPLN.SHIPMENTPLAN.PROCUREMENTPLAN .这三个表都是执行StartFP中的exportFP进行数据导 ...

  7. JQuery Mobile 页面参数传递(转)

    在单页模版中使用基于HTTP的方式通过POST和GET请求传递参数,而在多页模版中不需要与服务器进行通信,通常在多页模版中有以下三种方法来实现页面间的参数传递. 1.GET方式:在前一个页面生成参数并 ...

  8. 修改Tomcat根目录

    在server.xml文件中找到</Host>标签,在之前加入这样一行:<Context path="" docBase="F:/MyWeb" ...

  9. (四) 一起学 Unix 环境高级编程(APUE) 之 系统数据文件和信息

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  10. iOS页面间传值的方式(Delegate/NSNotification/Block/NSUserDefault/单例)

    iOS页面间传值实现方法:1.通过设置属性,实现页面间传值:2.委托delegate方式:3.通知notification方式:4.block方式:5.UserDefault或者文件方式:6.单例模式 ...