我正在使用Laravel 5.3中的日程安排。以前,我使用一台服务器来托管laravel应用程序。现在我使用两台服务器来运行Laravel App,如何确保两台服务器不同时运行相同的作业?
最近,我看到一个名为“withoutOverlapping()”的Event方法。见https://laravel.com/docs/5.3/scheduling#preventing-task-overlaps
就我而言, withoutOverlapping()无法帮助我,因为我在群集环境中工作。
对此有任何变通方法或建议吗?
答案 0 :(得分:1)
这是我在遇到负载均衡问题时所做的事情:
<%= l(post.the_created_at.to_date, format: :long) %>
然后你可以编写命令:
class MutexCommand extends Command {
private $hash = null;
public function cleanup() {
if (is_string($this->hash)) {
Redis::del($this->hash);
$this->hash = null;
}
}
protected abstract function generateHash();
protected abstract function handleInternal();
public final function handle() {
register_shutdown_function([$this,"cleanup"]);
try {
$this->hash = $this->generateHash();
//Set a value if it does not exist atomically. Will fail if it does exist.
//Essentially setnx is the mechanism to acquire the lock
if (!Redis::setnx($this->hash,true)) {
$this->hash = null; //Prevent it from being cleaned up
throw new Exception("Already running");
}
$this->handleInternal();
} finally {
$this->cleanup();
}
}
}
然后,每当您尝试在多个实例上运行相同的命令时,就会成功获得&#34;锁定&#34;而其他人应该失败。
当然,这假设您使用的是非群集redis缓存。
如果您不使用redis,那么您可以在其他缓存中实现类似的锁定机制,如果您使用的是群集redis,那么您可能需要使用RedLock锁定机制
答案 1 :(得分:0)
基本上没有,使用Laravel知道另一个Laravel应用程序是否在作业调度程序上具有相同的作业是不自然的。
我们有一些选择可以找到解决方案:
创建一个管理其他应用中作业的中间应用。
只允许一个应用分发作业。
使用工作队列,你有一些包,我建议使用PizzaTestDrive。
答案 2 :(得分:0)
首先,定义是否重要,以避免多次运行任务。 例如,如果您的应用程序正在使用任务进行某种清理,那么在每台服务器上运行它几乎没有任何缺点(如果您尝试使用+10分钟两次删除邮件,谁会在意?)
如果只运行一次每个任务绝对至关重要,那么您需要定义一个将执行任务的“主服务器”,以及一个只响应请求但不执行任何任务的从服务器。这非常简单,因为您只需在.env中为每个env指定一个不同的名称,并在定义调度程序任务时对其进行测试。
这是最简单的方法,严重的是不要打扰数据库锁定机制或其他什么,以便您可以同步服务器上的任务。即使操作系统努力管理同一台机器上的线程的正确同步,你为什么要在不同的机器上实现相同的操作呢?
答案 3 :(得分:0)
首先,Laravel调度程序不适用于集群环境。从来没有打算这样做。
我建议您应该有一个专用的cron实例来管理您的Laravel调度程序作业。