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

查看:820
本文介绍了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!');
        });

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

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()函数从不执行,并且阻止了下一个函数raisedFailedJobEvent()的调用.就像脚本在调用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.

更新:

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

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]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'unserialize():

如果我实际上进入vendor/laravel/framework/src/Illuminate/Queue/Worker.php,并在每次运行时强制其失败(当然,这是一种无例外的方式),那么就会调用failure().显然,问题是我如何知道该队列在实际故障中的行为?如果损坏的数据库数据导致失败,但又阻止了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?

推荐答案

从我与Graham在

Try this out from my conversation with Graham at https://github.com/laravel/framework/issues/9799

最后,我能找到的最完美的解决方案是在作业类本身上触发fail()方法,是将以下内容添加到EventServiceProvider.php的boot()方法中.捕获触发的完全失败事件,然后找出命令/作业并反序列化以调用fail()方法.

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天全站免登陆