大约有一年整没有写一篇博客了,由于各种原(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. VBS编辑字段

    '为已经创建好的数据表添加字段'参数:strDBPath 字符串型 数据库路径'参数:strTableName 字符串型 需要创建的数据表的名称'参数:strColumnName 字符串型 需要添加的 ...

  2. MAT内存问题分析定位

    MAT内存问题分析定位 1.下载安装MemoryAnalyzer工具. 2.使用DDMS将对应线程的内存日志导出来后,使用hprof-conv工具进行转换,用MAT打开转换后的hprof文件.

  3. 8.1H5学习笔记

    内嵌框架 说明: 属性 属性值 说明 width px,% 指定框架的宽度 height px,% 指定框架的高度 scrolling yes,no,auto 是否显示滚动条 frameborder ...

  4. XproerIM V1,2,12,65376 发布。

    客户端下载:http://yunpan.cn/QTCxKvcpC4Iet  访问密码 9141 更新说明:1.增加表情功能. 更新代码截图:

  5. Python list方法总结

    1. 向列表的尾部添加一个新的元素 append(...) L.append(object) -- append object to end 1 2 3 4 >>> a = ['sa ...

  6. 面向服务体系架构(SOA)和数据仓库(DW)的思考基于 IBM 产品体系搭建基于 SOA 和 DW 的企业基础架构平台

    面向服务体系架构(SOA)和数据仓库(DW)的思考 基于 IBM 产品体系搭建基于 SOA 和 DW 的企业基础架构平台 当前业界对面向服务体系架构(SOA)和数据仓库(Data Warehouse, ...

  7. C# 根据包含文件的路径和文件的名称的字符串获取文件名称的几种方法

    C# 截取带路径的文件名字,扩展名,等等 的几种方法 C#对磁盘IO操作的时候,经常会用到这些,路径,文件,文件名字,文件扩展名. 之前,经常用切割字符串来实现, 可是经常会弄错. 尤其是启始位置,多 ...

  8. ZMQ 在linux进程 和分布式之间的通信

    ZMQ 在linux进程 和分布式之间的通信 待补全

  9. MATLAB - 练习程序,求灰度图像均值、最大、最小数值

    clear all; close all; clc img=imread('lena.bmp'); figure; imshow(uint8(img)); [m n]=size(img); img_m ...

  10. 《CSS3秘籍》(第三版)-读书笔记(4)

    第12章  CSS页面布局 网页布局的类型: 固定宽度.不管浏览器窗口的宽度多大,网页内容的宽度始终保持不变. 流式.流式设计采用百分比,它会根据浏览器的宽度(无论有多宽)自动进行调整.网页会随着访问 ...