代码单测EOF问题解决过程
代码单测EOF问题解决过程
1. 发现问题
8月16日,应用研发同事反馈,代码提交后执行代码检查时失败,导致代码不能正常合入主干。
正常的流程是:提交代码 -> 执行单测(jacoco-maven)-> 解析单测结果(sonar-jacoco) -> 打包
查看日志,发现是解析单测结果的时候发生EOFException。这个异常表明sonar在读取解析单测结果时发生的问
题,就去排查sonar-jacoco插件的问题。
2. 怀疑sonar
在查找资料的过程发现,jacoco官方最初在旧版本中就是吃掉这个异常的,后面为了更好的暴露问题将EOF异常
抛出。旧版中发生EOF异常sonar会认为单测各种覆盖率等为零。
我于是掉头回去研究要解析的文件内容。正常来讲,执行完单测,jacoco会生成一个jacoco.exec的文件,但是发
现磁盘上这个文件是空的。那么是jacoco-maven在单测环节出问题了?
3. 怀疑jacoco
执行单测的命令时:
阅读jacoco-maven插件相关的文档得知,jacoco是通过JVM的shutdown提供的钩子将单测结果写入磁盘的,而
且是同步的写入的。
在调整提交代码文件的过程中,偶然间发现,这个问题是是偶发的,随机出现的。将代码复制到一个临时文件
夹,重复执行单测命令,发现jacoco.exec时而有内容,时而为空,确定问题是由jacoco引发的。翻查jacoco官方
的issue列表,果然有人遇到同样的问题,jacoco-issue-394,根据大家的讨论得知,问题是由jdk的bug引发的。
在java官方issue中确认了这个问题,一些低版本的jdk中,shutdown主线程会调用钩子线程的join,寄希望于钩
子线程执行完成后在结束主线程,但是如果应用程序中代码主线程调用了interrupt方法的话,会造成关闭指令和
钩子程序形成竞争,如果钩子程序竞争失败,那么文件写入不能完成,jacoco.exec即为空。
项目中全局搜索发现很多单测用例中调用了interrupt方法,再检查我们线上的jdk中ApplicationShutdownHooks
源码,问题确认了!
4. 升级JDK验证
下载最新版本的jdk,重复执行单测命令10次,稳稳的通过。跟团队确认jdk升级流程后将线上4台机器jdk全部升
级,邀请应用研发同事验证多次,编译环节单测均完美通过。
5. 思考
1 mvn org.jacoco:jacoco-maven-plugin:prepare-agent clean test -U
因为以前没人报过类似的问题,所以刚开始以为是提交代码的问题,然后逐个文件筛查,浪费了好多时间。
以后还是要事实求是,根据现场证据科学推断,不要经验主义。
开源组件的官方平台是解决问题的最好的途径,要保持关注,学会使用,善于利用官方提供的资料解决问
题