由于误操作在<code>erlcron</code>设置了一个超过3个月后的定时任务。然后第二天之后发现每天的daily reset没有被执行,一些定时任务也没有被执行。瞬间感觉整个人都不好了,怎么无端端就不执行了呢。
通过排查日志,发现了以下报错:
我擦,<code>ecrn_control</code>都崩了,怎么回事。
找到具体出错的代码:
发现调用<code>ecrn_reg:get(AlarmRef)</code>被返回了{ok, List},而且这个List的数据远不止一个。明显在设置那个超过3个月的定时任务的时候,<code>ecrn_reg</code>被注册进了脏数据。
查看<code>observer:start()</code> 可以看到进程树如下:
结果就gg了,好多崩溃信息是不是:
再看一下进程数:
我擦,为毛原来的 scrn_agent 进程也没有了。
可以发现,erlcron 在尝试了25次设置 这个定时任务之后,也就是 scrn_agent 崩溃了25次之后,原来设置的三个正常的定时任务的scrn_agent 进程也没有掉了。 也就是说,不但我新设置的定时任务没有成功,而且我原来正常的定时任务也没有掉了。
再看一下崩溃日志里面的崩掉的进程号,每一个都是不一样的。可以推算其实原来的报错<code>ecrn_reg:get(AlarmRef)</code>获取到了多个Pid,其实就是这里插入失败的定时任务产生的25个Pid。也就是说,虽然<code>ecrn_agent</code>进程崩溃了,但是<code>ecrn_reg</code>还是保存了这些Pid。所以在取消这些定时任务的时候,<code>ecrn_reg:get(AlarmRef)</code>返回的内容在<code>internal_cancel(AlarmRef)</code>没有被匹配到。
为什么设置了<code>4294968</code>秒后的定时任务就崩溃了。这个数估计很多人很熟悉,<code>2^32=4294967296</code>,而<code>4294968000</code>也就是刚好大于<code>2^32</code>。即,如果设置的定时任务超过了<code>2^32</code>毫秒,在<code>erlcron</code>里面就不支持了。
查看<code>gen_server:loop</code>的源码,找到引起崩溃的代码:
可以发现引起崩溃的,358行是一段<code>receive</code>代码。也就是说<code>receive</code>是不支持超过<code>2^32</code>大小的。
自测了一下,的确如果<code>receive</code>的<code>after</code>后面如果是大于等于<code>2^32</code>的数值就会出现<code>bad receive timeout value</code>的报错。查看官方解释,已经明确说明不能大于<code>32位</code>大小。
ExprT is to evaluate to an integer. The highest allowed value is 16#FFFFFFFF, that is, the value must fit in 32 bits. receive..after works exactly as receive, except that if no matching message has arrived within ExprT milliseconds, then BodyT is evaluated instead. The return value of BodyT then becomes the return value of the receive..after expression.
引用自:http://erlang.org/doc/reference_manual/expressions.html
再回到<code>erlcron</code>, 在 <code>ecrn_agent:start_link</code>的时候,<code>ecrn_agent:init</code>执行完<code>ecrn_reg:register(JobRef, self())</code>返回<code>{ok, NewState, Millis}</code>到<code>gen_server</code>之后,Millis如果超过<code>2^32</code>在<code>gen_server:loop</code>就会引起<code>gen_server</code>的<code>timeout_value</code>异常退出。
这坑踩的,有点郁闷。其实这跟<code>erlcron</code>也没关系,也不是<code>gen_server</code>的问题。而是<code>erlang</code>自身<code>receive</code>不支持2^32引起的。继续往下查其实可以发现,再往下是其它语言写的了。
与君共勉
本文转自 Ron Ngai 博客园博客,原文链接:http://www.cnblogs.com/rond/p/5315204.html ,如需转载请自行联系原作者