线上定时任务长时间未结束问题诊断
文章目录
最近线上经常出现定时任务长时间运行不结束的问题,最终通过日志及线程堆栈分析定位到具体代码从而得到解决。
业务流程
我们有一个定时任务,定期读取数据库中邮箱身份验证信息(暂且称之为EmailAuthentication
),并通过JavaMail使用EmailAuthentication
来读取邮件以进行后面的一些业务流程。
现象
最近发现部分EmailAuthentication
会长时间处于运行中状态。因为除了这个现象外,还偶尔会有内存溢出的问题,一开始以为这是由内存溢出
导致虚拟机崩溃导致应用程序没有将EmailAuthentication
设置为未运行而造成。后来给JVM加上-XX:+HeapDumpOnOutOfMemoryError后,没有出现过内存溢出
,但是问题依旧存在。
问题定位
在现有日志中未找到问题,我尝试从代码中找。之后发现尽管定时任务是多线程,但是代码配合乐观锁和事务,在虚拟机不崩溃的情况下EmailAuthentication
最终都会是设置成未运行。
那么就只有一种可能了,应用程序还没有跑到最后一步,在某个地方卡住了。
为了验证这种可能性以及定位问题,我在定时任务的第一步和最后一步分别加上了log
|
|
|
|
果然,出现问题的EmailAuthentication
,只打印了第一条日志。
线程名SimpleAsyncTaskExecutor-8467
(不要在意线程的名字,我也知道线程池不应该用SimpleAsyncTaskExecutor)
发现问题的第一时间我就使用jps
和jstack
,先把堆栈信息弄到手。后来发现,我可以直接用arthas
,太香了。
然后直接进行一个
|
|
找到SimpleAsyncTaskExecutor-8467
然后再进行一个
|
|
好!问题找到了,就是这个MailUtil.fetchMail
。
解决
用脚想想,那应该是MailUtil.fetchMail
没有设置超时时间了。
倒一倒JavaMail的源码。可以在SocketFetcher.getSocket
中看到。
|
|
默认值为-1
(无限超时)
所以,设置一下这两个值就好了。我们用的pop3,所以给Properties设置的属性为
|
|
单位是毫秒。