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 协议》,转载必须注明作者和本文链接
刻意练习,每日精进
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 4

@Complicated 使用withoutOverlapping就好了,内部实现了文件锁

5年前 评论
glowb 4年前
          • /home/deploy/code/single.sh

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

可以考虑一下这个做法!

4年前 评论
Complicated

这种问题之前也遇到过,我的办法比较粗暴,在库里有个配置项,定时任务一起来就去检查这个配置项 true就执行作业,false就直接结束定时任务。当一个定时实例开始,就把这个配置项改成false,结束的时候改成true。这样还是会起实例,但是任务不会重复执行

5年前 评论

格式完全乱了

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!