集群环境中的Laravel调度

时间:2017-11-28 15:21:12

标签: laravel

我正在使用Laravel 5.3中的日程安排。以前,我使用一台服务器来托管laravel应用程序。现在我使用两台服务器来运行Laravel App,如何确保两台服务器不同时运行相同的作业?

最近,我看到一个名为“withoutOverlapping()”的Event方法。见https://laravel.com/docs/5.3/scheduling#preventing-task-overlaps

就我而言, withoutOverlapping()无法帮助我,因为我在群集环境中工作。

对此有任何变通方法或建议吗?

4 个答案:

答案 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调度程序作业。