首页 文章

Laravel 5.1失败的排队作业在failed()方法失败,防止调用队列失败事件处理程序

提问于
浏览
6

我正在测试Laravel 5.1中的队列功能 . 我可以在我的数据库表中将作业排队,称为作业,我可以让它们成功运行 . 我还创建了一个名为failed_jobs的队列故障表 . 为了测试它,在jobs表中我操纵有效负载数据使其失败然后我像这样运行队列工作守护进程,所以它会在一次失败尝试后将作业放入failed_jobs表中:

php artisan queue:work --daemon --tries=1 --queue=myqueue

当作业失败时,它会立即按预期放入failed_jobs表中 .

仅供参考我就像Laravel 5.1文档推荐的那样:

http://laravel.com/docs/5.1/queues#dealing-with-failed-jobs

我已经尝试在AppServiceProvider的boot()方法中注册我的队列失败事件,如文档中所述:

Queue::failing(function ($connection, $job, $data) {
            Log::error('Job failed!');
        });

我也在实际的作业脚本中尝试了fail()方法,如下所示:

/**
         * Handle a job failure.
         *
         * @return void
         */
        public function failed()
        {
            Log::error('failed!');
        }

无论哪种方式,当排队的作业失败时都不会触发这些事件 . 我在日志中看不到任何内容,除了我故意发生的异常堆栈跟踪 . Laravel 5.1在这里有错误还是我遗漏了什么?

更新:

我做了一些更多的研究 . 当发生队列作业失败时,处理该失败的逻辑在vendor / laravel / framework / src / Illuminate / Queue / Worker.php中:

protected function logFailedJob($connection, Job $job)
    {
        if ($this->failer) {
            $this->failer->log($connection, $job->getQueue(), $job->getRawBody());

            $job->delete();

            $job->failed();

            $this->raiseFailedJobEvent($connection, $job);
        }

        return ['job' => $job, 'failed' => true];
    }

失败的()函数永远不会执行,它会阻止调用下一个函数raiseFailedJobEvent() . 就好像脚本在调用failed()时静默停止 . 现在,如果我颠倒这些行的顺序,我可以触发raiseFailedJobEvent(),如果我在EventServiceProvider.php或AppServiceProvider.php中注册一个队列事件处理程序,我可以验证它被触发,我可以成功处理该事件 . 不幸的是,在raiseFailedJobEvent()之前失败()会阻止此事件发生 .

更新:

问题似乎源于我如何使其失败 . 如果我故意破坏作业队列表中的数据,则永远不会调用failed()方法 . 日志中有一个堆栈跟踪:

Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'unserialize():

如果我实际进入vendor / laravel / framework / src / Illuminate / Queue / Worker.php并在每次运行时强制它失败(当然是以无异常的方式),则调用failure() . 显然,问题是如何知道这个队列在真实世界中的失败?如果损坏的数据库数据导致失败但仍然阻止调用fail(),则这是不好的 . 如果现实世界中存在db队列数据的实际损坏怎么办?

2 回答

  • 2

    在我与格雷厄姆的谈话中尝试这一点https://github.com/laravel/framework/issues/9799

    最后,我可以找到最优雅的解决方案来获取在工作类本身上触发的failed()方法,就是在下面添加EventServiceProvider.php的boot()方法 . 捕获已触发的完整失败事件,然后挖掘命令/作业并将其反序列化以调用failed()方法 .

    Queue::failing(function($connection, $job, $data)
            {
                $command = (unserialize($data['data']['command']));
                $command->failed();
            });
    
  • 9

    如果你像这样启动队列监听器

    nohup php artisan queue:listen > storage/logs/queue.log 2>&1 &
    

    然后将自动创建并填充队列日志文件 .

相关问题