虽然都是运行在JVM之上的语言,看起来在字节码层面上一样,不过混合编程有时候还是有...
问题描述
项目升级改造,部署时遇到下面问题。
1 发现已经下发了命令,但是设备没有动作。
发现项目1.0版本与2.0版本的设备id不一样。
2 临时添加设备id的映射关系,旧的id转换为新的设备id即可
发现一直报错,表达式解析错误,命令无法下达到底层应用。使用了QLExpression规则引擎,可以动态的执行规则脚本。
线上无法直接调试,框架内错误信息提示不明显。
干扰因素
- 本人对日常环境的所有流程比较清晰,可能出现的问题也知道。比如在日常环境云端处理规则,可能无法下发到本地。测试不知情,我让测试帮我更新一下日常的规则,导致日常不是最新的规则
- 日常不是最新的规则,日常环境就与线上不一致,问题无法再现
- 出现问题时,不够冷静,在问题出现没多久,通过模拟勉强达到了与线上差不多的数据。但是没有完全执行规则,比如线上规则有5句话,日常只测试了4句话,都是成功的,就以为规则是成功的,实际规则问题是在第5句。规则不仅仅是5句话而已,而是一句话被包装了5次,这种情况最容易出现各种各样的问题
定位问题
早上来到公司,没人的情况下头脑清晰,开始处理问题。
1 处理日常环境,试日常环境与线上环境保持一致。以便再现问题
2 关键部分加上断点
3 调试问题
问题点
以下是出现问题的规则:
setPoint(_states_,deviceIds.get(queryBoxRight.data.data.get(0)),"Lock_control","true")
拆解:
queryBoxRight.data.data.get(0) ==> 执行成功
deviceIds.get(queryBoxRight.data.data.get(0)) ==> 执行成功
setPoint(states,deviceIds.get(queryBoxRight.data.data.get(0)),"Lock_control","true") ==> 执行失败
报错信息:ClassCastException
疑问
为什么会报ClassCastException
?
查看:deviceIds.get(queryBoxRight.data.data.get(0)) ==> scala.Some
查看:setPoint(states: States,deviceId: String, code: String, value: String): Unit
原因
scala.Some != java.lang.String,无法强制转换。
多次Scala语法尝试
// scala获取String的方法
deviceIds.get(queryBoxRight.data.data.get(0)).getOrElse()
// 结果:报错,无法调用getOrElse()方法。
// scala获取Some中的值,报错
deviceIds.get(queryBoxRight.data.data.get(0)).value
// scala获取Some值的方法,报错
deviceIds.get(queryBoxRight.data.data.get(0)).get
尝试Scala Decompile之后的class文件语法尝试
//成功
deviceIds.get(queryBoxRight.data.data.get(0)).value()
deviceIds.get(queryBoxRight.data.data.get(0)).get()
结论
QLExpression执行规则语句,只支持java语法,或者decompile为Java文件的语法。不要直接用Scala的语法写规则。
反思
1 遇到问题仍然要保持冷静,不能嫌麻烦,仍然需要一步一步来,越偷工减料,越找不到问题真正原因
2 不要有侥幸心理,当以为都试过了,其实还差一步没有试的时候,问题出现在了最后一步。尽可能还原真实场景,尽可能追求一模一样