文本描述了偶发付款单无法提交至工作流的问题。经分析,发现是由于RPC异步线程池未在工作线程完成时恢复工作流线程变量的初始值,导致线程复用时未触发工作流。解决方案包括修改配置文件禁用RPC异步线程池、修复异步线程池未触发监听的问题、加固凭证业务代码确保工作流服务正确开启,并完善日志打印以便于问题追踪。
问题现象:偶发付款单提交不进工作流
问题分析:
1、worfklow.log通过搜到提交的单据id找到异常日志。
可知是该线程中工作流服务开关线程变量(ThreadLocal)中的值已经被改成false,导致不触发工作流。
2、而奇怪的是,付款单提交操作,日志中记录的是凭证提交方法中修改的工作流服务开关变量为关闭。
经业务同事再三分析确认,付款单提交方法中并没有调用凭证相关方法,因此这里陷入疑点。
3、此时我们的思路来到线程本身,我们知道业务操作的请求到EAS服务端会通过RPC线程池去调度,那么这里面存在线程复用,会不会是凭证提交的RPC线程刚好执行完成,然后被再次用来执行付款单提交方法。显然是会的。
4、于是我们分析工作流服务开关类相关代码(WfEventListenerStateManager),发现该类初始化时就会加入RPC线程池的一个监听(ThreadListener),在线程执行完成时(threadFinished(Thread thread);)会将该线程变量恢复初始值null,这样就可以保证RPC线程即便被复用也不会串线程变量。
5、那么是否是由于没有触发该监听导致的呢?
经过框架同事协助分析发现,RPC线程池当前分为同步或异步,然后RPC异步线程池没有实现线程完成时的方法,即没有在线程完成时去调用该监听类的threadFinished(Thread thread);方法,则无法将该线程变量恢复初始值null,当被该线程复用到下一个业务方法调度时就不会触发工作流校验了。
6、经核实,配置文件eas\server\profiles\server*\config\目录下的ormrpc_eas.propertie配置文件,isAsync=true 确实是启用了RPC异步线程池导致。
(这里有个背景:默认EAS公有云环境该异步线程池会开启,由于很多公有云环境服务器默认有请求超时限制)
分析小结:
问题到这里,基本破案。根因:启用RPC异步线程池之后工作流线程变量ThreadLocal没有在线程结束时恢复初始值。
最终解决措施:
1、该客户之前是公有云环境,后来已经改为私有云,经测试了下其实还是有超时机制。
但是为避免该类问题发生,还是建议把修改ormrpc_eas.propertie配置文件,删除isAsync=true或把true改成false
2、对于RPC异步线程池没有实现线程完成方法触发ThreadListener 的threadFinished(Thread thread)的问题,框架同事出了私包修复。
修复后的代码如下:
3、凭证业务同事出私包加固:保证凭证业务方法调用完成之后必定会将工作流服务开启。
4、其他:工作流这块完善日志打印,将修改工作流线程变量的线程名称打印出来等等。