Laravel 定时任务,避免重复的方法-----使用文件锁
有时一个预定的工作需要比我们最初预期的更多的时间运行,这样会导致另外一个工作的实例开始,而第一个还没有完成,例如,我们运行一个每分钟生成报告的工作有时候当数据变大时,报表生成可能需要 1 分钟以上,这样就可以在第一个还在进行时启动该作业的另一个实例。
在大多数情况下,这是很好的,但有时候应该防止这种情况,以保证正确的数据或防止高的服务器资源消耗,所以让我们看看如何防止这种情况在 laravel 中发生:
$schedule->command('mail:send')->withoutOverlapping();
Laravel 将检查 Console\Scheduling\Event::withoutOverlapping
类属性,如果设置为 true,它将尝试为作业创建互斥,并且只有在创建互斥的情况下才能运行该作业。
但是上面是互斥?这是我可以在网上找到最有趣的解释:
当我在工作中进行热烈的讨论时,我使用一只橡胶鸡,我在这样的场合放在桌子上。 持有鸡的人是唯一被允许谈话的人。 如果你不握鸡,你不会说话。 你只能指示你想要鸡,等到你说话之前才能得到它。 一旦你完成演讲,你可以将鸡回到主持人,他将把它交给下一个人说话。 这样可以确保人们互不说话,也有自己的空间。 用线替换鸡与互斥和人,你基本上有一个互斥的概念。
–https://stackoverflow.com/questions/34524/what-is-a-mutex/34558#34558
所以当作业第一次启动时,Laravel 创建一个互斥,然后每次作业运行时,它检查互斥是否存在,只有在没有工作的情况下运行。这里是 withoutOverlapping 方法中做的事
``public function withoutOverlapping()
{
$this->withoutOverlapping = true;
return $this->then(function () {
$this->mutex->forget($this);
})->skip(function () {
return $this->mutex->exists($this);
});
}
``
因此,Laravel 创建一个 filter-callback 方法,指示 Schedule Manager 忽略任务,如果互斥仍然存在,它还会创建一个在完成任务实例后清除互斥的回调。
在运行该作业之前,Laravel 会在Console\Scheduling\Event::run()方法中进行以下检查:
``if ($this->withoutOverlapping && ! $this->mutex->create($this)) {
return;
}``
互斥体属性来自哪里?
当 Console\Scheduling\Schedule 的实例被实例化时,laravel 会检查 Console\Scheduling\Mutex 接口的实现是否绑定到容器,如果是,则使用该实例,如果不是,使用Console\Scheduling\CacheMutex实例:
``$this->mutex = $container->bound(Mutex::class)
? $container->make(Mutex::class)
$container->make(CacheMutex::class); 现在,Schedule Manager 正在注册你的事件,它会传递互斥的一个实例:
$this->events[] = new Event($this->mutex, $command); 默认情况下,Laravel 使用基于缓存的互斥,但您可以覆盖它并实现自己的互斥方法并将其绑定到容器。 基于缓存的互斥 CacheMutex 类包含 3 个简单的方法,它使用事件互斥名作为缓存键:
public function create(Event $event)
{
return $this->cache->add($event->mutexName(), true, 1440);
} public function exists(Event $event) { return $this->cache->has($event->mutexName()); }
public function forget(Event $event)
{
$this->cache->forget($event->mutexName());
} ###任务完成后的互斥删除 如前所述,管理器注册一个在完成任务之后删除互斥的回调,对于在操作系统上运行命令的任务可能足以确保互斥被清除,但是对于回调 执行回调时脚本可能会死机,所以为了防止这种情况在 `Console\Scheduling\CallbackEvent::run()`中添加了一个额外的回退:
register_shutdown_function(function () {
$this->removeMutex();
});``
本作品采用《CC 协议》,转载必须注明作者和本文链接
这种问题之前也遇到过,我的办法比较粗暴,在库里有个配置项,定时任务一起来就去检查这个配置项 true就执行作业,false就直接结束定时任务。当一个定时实例开始,就把这个配置项改成false,结束的时候改成true。这样还是会起实例,但是任务不会重复执行
@Complicated 使用withoutOverlapping就好了,内部实现了文件锁
格式完全乱了
single.sh
LOG="/tmp/code.log"
ROOT="/var/www/{目录}"
TIME=
date '+%Y-%m-%d %H:%M:%S'
PIDS=
ps aux | grep schedule:run | grep -v grep
if [ -z "$PIDS" ]; then
echo "$TIME Starting artisan schedule ..." >> $LOG
/usr/bin/php $ROOT/artisan schedule:run >> $LOG 2>&1
DONE=
date '+%Y-%m-%d %H:%M:%S'
echo "$DONE Artisan schedule completed." >> $LOG
else
echo "$TIME Artisan schedule already running." >> $LOG
fi
可以考虑一下这个做法!