Laravel 5.1 失败的排队作业在 failed() 方法上失败,防止调用队列失败事件处理程序 [英] Laravel 5.1 failed queued jobs fails on failed() method, prevents queue failure event handler from being called

查看:83
本文介绍了Laravel 5.1 失败的排队作业在 failed() 方法上失败,防止调用队列失败事件处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am testing the queue functions in Laravel 5.1. I can make jobs queue up in my db table, called jobs, and I can get them to run successfully. I also created a queue failure table called failed_jobs. To test it, inside the jobs table I manipulate the payload data to make it fail then I run the queue worker daemon like so, so it will put the job in the failed_jobs table after one failed attempt:

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

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

When the job fails it is immediately put into failed_jobs table as expected.

仅供参考,我已经按照 Laravel 5.1 文档推荐的方式进行了设置:

FYI I have set things up just like the Laravel 5.1 docs recommend:

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

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

I have tried registering my queue failure event in the AppServiceProvider's boot() method as outlined in the docs:

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

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

I have also tried the failed() method inside the actual job scripts like so:

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

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

Either way, neither of these events is triggered when the queued job fails. I see nothing in the logs except for the exception stack trace which I made occur on purpose. Does Laravel 5.1 have a bug here or am I missing something?

更新:

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

I have done some more research. When a queue job failure occurs, the logic for handling that failure is in 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() 可以防止此事件发生.

What happens is the failed() function never executes and it prevents the next function, raisedFailedJobEvent() from being called. It's as if the script silently halts when failed() is called. Now if I reverse the order of these lines, I can get the raiseFailedJobEvent() to fire and if I register a queue event handler in EventServiceProvider.php or AppServiceProvider.php, I can verify it gets fired and I can successfully handle the event. Unfortunately, having failed() before raiseFailedJobEvent() prevents this event from ever occurring.

更新:

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

The problem seems to stem from how I make it fail. If I deliberately corrupt the data in the job queue table, the failed() method never gets called. There is a stack trace in the logs:

Stack trace:
#0 [internal function]: IlluminateFoundationBootstrapHandleExceptions->handleError(8, 'unserialize():

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

If I actually go into vendor/laravel/framework/src/Illuminate/Queue/Worker.php and force it to fail every time it runs (in an exception-less way of course), then failure() gets called. The problem, obviously, is how do I know how this queue will behave in a real-world failure? If corrupt db data causes a failure yet prevents failure() from being called, this is no good. What if there is an actual corruption of db queue data in the real world?

推荐答案

从我在 https://github.com/laravel/framework/issues/9799

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

In the end the most elegant solution I could find to get the the failed() method to trigger on the job class itself was to add to the below to the boot() method of EventServiceProvider.php. Catching the full fail event that is fired and then digging out the command/job and unserializing it to call the failed() method.

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

这篇关于Laravel 5.1 失败的排队作业在 failed() 方法上失败,防止调用队列失败事件处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆