停止通过cron作业运行的并发php作业作业

时间:2017-11-29 15:21:49

标签: php shell cakephp cron queue

我使用Queshadilla作业队列插件为CakePhp管理几个重型任务,从excel中提取数据等等。我用一个间隔的cron作业运行shell命令。但是,如果队列中列出了多个作业; shell命令在下一个作业上启动worker而不等待前一个作业的结束或失败。因为我想以非常小的间隔运行shell命令为5秒,并且一些作业需要3分钟才能完全运行;我希望工人等待上一份工作完成,直到那时才开始。

然而,当我用bin/cake CustomQueuesadilla运行cronjob时;很明显,它开始于一个新的PID等,而不知道前一个是否还在运行。当我将worker的运行时间设置为20秒并将cron作业间隔设置为3分钟时;我每3分钟就有一份工作。但这也意味着如果没有工作,它将等待3分钟 - 20秒再次运行。我想减少这个时间窗口。

我也对架构变化和不同的库开放。

1 个答案:

答案 0 :(得分:2)

Queue vs Cron

您尝试实施的是循环队列。 Cron仅适用于预定活动。

  1. 构建您的队列管理器/工作者
    • 此工作人员calls the other commands
    • 此类调用应包含在try / catch中,并检查退出代码。
    • 您应该记录每次通话的(time, command [, error])
    • 将其构建为单身人士。
  2. 添加一个cron条目来调用获取Manager(单例)的命令。
    • 由于单例模式,如果停止,它将再次启动。
    • 除非您将队列的状态存储在该Manager(文件或数据库)之外,否则它可能总是在cmd4处死亡,并且永远不会运行后续命令。
  3. 经理

    class CommandQueueLoop {
        const QUEUE = [
            'app:command1' => [
                'command' => 'app:command1',
            ],
            'app:command2' => [
                'command' => 'app:command2',
                'somearg' => 123
            ],
            'app:command3' => [
                'command' => 'app:command3',
            ],
        ];
    
        private static $queueManager;
    
        private $activeQueue;
        private $app;
        private $input;
        private $output;
        private $running;
    
        public function __construct(Application $app, InputInterface $input, OutputInterface $output)
        {
            $this->app = $app;
            $this->input = $input;
            $this->output = $output;
            $this->running = false;
            $this->start();
        }
    
        public static function getInstance(Application $app, InputInterface $input, OutputInterface $output)
        {
            if (!self::$queueManager instanceof self) {
                self::$queueManager = new self();
            }
        }
    
        public function start(array $queue = null)
        {
            $this->activeQueue = $queue ?? self::QUEUE;
            $this->running = true;
            $this->run($this->activeQueue);
        }
    
        public function stop()
        {
            $this->running = false;
            $this->activeQueue = null;
        }
    
        private function run(array $queue)
        {
            if (!$this->running) {
                return;
            }
    
            foreach ($queue as $cmd => $args) {
                $this->call($cmd, $args);
            }
    
            $this->run($this->activeQueue);
        }
    
        private function call(string $command, array $args)
        {
            try {
                $cmd = $this->app->find($command);
                $inp = new ArrayInput($args);
                $returnCode = $cmd->run($inp, $this->output);
            } catch (Exception $e) {
                // log failure
                unset($this->activeQueue[$cmd]); // remove from queue
            }
    
            // check returnCode & log
        }
    }
    

    确保队列正在运行的Cron命令

    添加此命令,并且只将此命令添加到cron,每小时一次。当它运行时,如果命令已经停止,它将再次启动。

    class QueueLoopCommand extends Command
    {
        ...
    
        public function execute(InputInterface $input, OutputInterface $output)
        {
            $queueLoop = CommandQueueLoop::getInstance($this->getApplication(), $input, $output);
        }
    }
    

    这里是龙

    这位"经理"需要非常仔细地编写,具有良好的记录和某种紧急停止。另外,Cron Command应该在" manager"中调用其他方法的主机。检查状态,最后一次运行,仔细检查多个线程等,并对意外状态执行某些操作。像这样的建筑工具变得非常快,并且可以像你不相信的那样引导你钻掉兔子洞。

    主要危险:

    • 内存泄漏
    • 多个冲突的主题
    • 意外的竞争条件