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

标签 laravel queue laravel-5 jobs

我正在测试 Laravel 5.1 中的队列功能。我可以让作业在我的数据库表中排队,称为作业,并且可以让它们成功运行。我还创建了一个名为 failed_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!');
        });

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

/**
         * 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];
    }

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

更新:

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

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

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

最佳答案

从我与 Graham 的对话中试试这个: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();
        });

关于Laravel 5.1 失败的排队作业在 failed() 方法上失败,阻止调用队列失败事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31305571/

相关文章:

php - Laravel 搜索工具

php - Laravel 偶尔无法读取缓存

javascript - 对象属性在 $.ajax POST 请求中丢失

php - Laravel 家园 - 虚拟机 :The host path of the shared folder is missing: ~/Code on OSX Yosemite

java - 如何在Java中克隆BlockingQueue?

c - 带指针的 C 数组队列

php - Laravel mongodb ->getPdo() 返回 null

laravel - 如何显示用户的电子邮件而不是 id

php - 方法的声明必须与接口(interface)方法的声明兼容 - 当方法签名完全相同时?

python - 在python中实现循环队列-级别标准