【问题标题】:(Laravel 5) Monitor and optionally cancel an ALREADY RUNNING job on queue(Laravel 5) 监控并有选择地取消队列中的 ALREADY RUNNING 作业
【发布时间】:2019-07-02 22:16:22
【问题描述】:

我需要实现监控和取消队列中已经运行的作业的能力。

有很多关于删除 QUEUED 作业的答案,但没有一个已经在运行的作业。

情况是这样的:我有一个“工作”,它由数据库上的成千上万行组成,需要针对 Web 服务逐个查询。

需要提取每一行,针对 Web 服务进行查询,存储响应并更新其状态。

我已经将它作为命令工作(从控制台启动/输出到控制台),但现在我需要实现队列,以便从更多用户那里堆积更多工作。

到目前为止,我已经看到了 Horizo​​n(由于缺少进程控制库,它不能在 Windows 上运行)。但是,在周围看到的一些演示中,它缺少(我相信)我需要的几件事:

  • 可动态配置超时(整个作业可能需要 12 小时以上,具体取决于所选作业要处理的行数)
  • 能够取消已经运行的作业。

我还考虑了将每个请求生成为新作业的选项,而不是将“作业”视为整个行集合(这将克服超时问题),但这会给我一个 Horizo​​n“待定作业”列表每个作业有数十万条记录,这会杀死浏览器(我知道 Redis 可以完全不痒地处理这个问题)。此外,我想不可能取消“所有属于 X​​ 标签的工作”。

我一直在考虑使用 API 路由、启动作业并将其与应用程序分离,但我发现这需要分叉进程。

为了能够取消,我将使用 job_id 实现一个数据库,当用户点击 API 取消作业时,我会将其标记为“已暂停”。在每个循环中,我都会检查它的状态,如果它发现“已停止”,那么就杀死它自己。

如果我遗漏了任何方面,请大声疾呼,我会添加或澄清它。

所以我在这里寻求建议,因为我是 Laravel 的新手:我怎么能做到这一点?

【问题讨论】:

    标签: queue laravel-5.8


    【解决方案1】:

    所以我终于想出了这个(有点笨拙)的解决方案:

    在控制器中:

     public function cancelJob()
        {
            $jobs = DB::table('jobs')->get();
    
            # I could use a specific ID and user owner filter, etc.
            foreach ($jobs as $job) {
                DB::table('jobs')->delete($job->id);
            }
    
            # This is a file that... well, it's self explaining
            touch(base_path(config('files.halt_process_signal')));
    
            return "Job cancelled - It will stop soon";
        }
    

    在作业类中(在model::chunk() 函数内)

                    # CHECK FOR HALT SIGNAL AND [OPTIONALLY] STOP THE PROCESS
                    if ($this->service->shouldHaltProcess()) {
    
                        # build stats, do some cleanup, log, etc...
    
                        $this->halted = true;
                        $this->service->stopProcess();
    
                        # This FALSE is what it makes the chunk() method to stop looping
                        return false;
                    }
    

    在服务类中:

        /**
         * Checks the existence of the 'Halt Process Signal' file
         *
         * @return bool
         */
        public function shouldHaltProcess() :bool
        {
            return file_exists($this->config['files.halt_process_signal']);
        }
    
    
        /**
         * Stop the batch process
         *
         * @return void
         */
        public function stopProcess() :void
        {
            logger()->info("=== HALT PROCESS SIGNAL FOUND - STOPPING THE PROCESS ===");
            $this->deleteHaltProcessSignalFile();
    
            return ;
        }
    

    它看起来不太优雅,但它确实有效。 我浏览了整个网络,很多人都选择了 Horizo​​n 或其他不适合我的工具。 如果有人有更好的方法来实现这一点,欢迎分享。

    【讨论】:

    • 你从哪里得到这个? “配置('afip_client.files.halt_process_signal')”??
    • @Jonson 这是一个错误。查看当前行。它来自 /app/config.php > ['files' => ['halt_process_signal' => '/your/stop/signaling/file']]; 我希望它现在更清楚了。
    • 您能否分享您的代码的完整参考,以“监控并可选择取消队列中已运行的作业”!当然,如果你有空闲时间
    【解决方案2】:

    Laravel 队列有 3 个重要的配置:

    1. retry_after
    2. timeout
    3. tries
    

    查看更多:https://laravel.com/docs/5.8/queues

    动态可配置的超时时间(整个作业可能需要超过 12 小时,具体取决于所选作业要处理的行数)

    我认为你可以配置 timeout + retry_after 大约 24 小时。

    能够取消已经在运行的作业。

    • 删除作业表中的作业
    • 在您的服务器中按进程 ID 删除进程

    希望对你有帮助:)

    【讨论】:

    • 超时:24 小时。超时“以防万一”不是一种选择。仅仅为了被覆盖而浪费 12 小时是负担不起的。流程:框架的想法是消除这种解决方案的手工制作。当然总是考虑,但我们首先会避免。感谢您的回答!
    • 感谢您的回答,@alex。我刚刚发布了我找到的解决方案。
    • @fernandojmartin 是的。我明白了:D
    猜你喜欢
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    • 2016-09-02
    • 2016-03-24
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    相关资源
    最近更新 更多