项目中遇到Laravel的定时计划任务schedule开始是按照预期正常执行,但是偶然的一些因素,会发现一部分任务不再执行,但是其他的任务依然可以正常执行,分析后发现是schedule使用了withoutOverlapping的互锁机制导致的。
在laravel里,当我们使用了 withoutOverlapping 方法后,这个任务就会产生一个mutex标记(互锁文件实现),可以避免上一次的任务还在执行中,新的任务已经来了导致发生同时执行的情况。这个withoutOverlapping 方法,可以很好的避免同时执行的问题,让系统一次只执行一个任务。
正常情况下,这个互锁机制是很好的解决了同时并发的问题。互锁的原理:mutex标记是受Laravel框架的vendor/laravel/framework/src/Illuminate/Console/Scheduling/CacheMutex.php文件控制的,用的是.env中指定的CACHE_DRIVER(对应到config/cache.php中指定的配置),一般默认是file类型,对应到cache目录;具体的是laravel 5.5版本里会在config目录的cache.php文件里指定了缓存文件的目录,默认是 storage_path('framework/cache/data') 目录,比如某个任务会在执行的时候,产生一个物理文件,路径:
storage/framework/cache/data/f5/e6/f5e6059d5dd95d3be45e759a96d19ba831bc8ab4
文件内容是:
1715740989a:1:{s:11:"valid_until";i:1715568249;}
laravel通过这个文件来实现互锁机制,当这个文件存在时,就跳过本次任务。
但是当系统异常发生时(比如系统重启,无限循环,超时异常等),可能会导致这个文件一直不会被删除,那么后续就再也无法执行这个任务了。
解决方法也很简单:
rm -rf framework/cache/data/*
删除了上面的缓存目录后,系统的定时任务也就会恢复正常了。