Laravel 5.1 失败的排队作业在 failed() 方法上失败,防止调用队列失败事件处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31305571/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel 5.1 failed queued jobs fails on failed() method, prevents queue failure event handler from being called
提问by Joel Joel Binks
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:
我正在测试 Laravel 5.1 中的队列功能。我可以让作业在我的数据库表中排队,称为作业,我可以让它们成功运行。我还创建了一个名为 failed_jobs 的队列失败表。为了测试它,在作业表中,我操纵有效负载数据使其失败,然后我像这样运行队列工作器守护程序,因此在一次尝试失败后,它会将作业放入 failed_jobs 表中:
php artisan queue:work --daemon --tries=1 --queue=myqueue
When the job fails it is immediately put into failed_jobs table as expected.
当作业失败时,它会按预期立即放入 failed_jobs 表中。
FYI I have set things up just like the Laravel 5.1 docs recommend:
仅供参考,我已经按照 Laravel 5.1 文档的建议进行了设置:
http://laravel.com/docs/5.1/queues#dealing-with-failed-jobs
http://laravel.com/docs/5.1/queues#dealing-with-failed-jobs
I have tried registering my queue failure event in the AppServiceProvider's boot() method as outlined in the docs:
我已经尝试在 AppServiceProvider 的 boot() 方法中注册我的队列失败事件,如文档中所述:
Queue::failing(function ($connection, $job, $data) {
Log::error('Job failed!');
});
I have also tried the failed() method inside the actual job scripts like so:
我还在实际作业脚本中尝试了 failed() 方法,如下所示:
/**
* Handle a job failure.
*
* @return void
*/
public function failed()
{
Log::error('failed!');
}
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?
无论哪种方式,当排队作业失败时,都不会触发这些事件。除了我故意发生的异常堆栈跟踪之外,我在日志中看不到任何内容。Laravel 5.1 这里有错误还是我遗漏了什么?
UPDATE:
更新:
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:
我做了更多的研究。当队列作业失败时,处理失败的逻辑在 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];
}
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() 函数永远不会执行,它阻止了下一个函数 raiseFailedJobEvent() 被调用。就好像脚本在调用 failed() 时默默地停止了。现在,如果我颠倒这些行的顺序,我可以让 raiseFailedJobEvent() 触发,如果我在 EventServiceProvider.php 或 AppServiceProvider.php 中注册一个队列事件处理程序,我可以验证它是否被触发并且我可以成功处理该事件。不幸的是,在 raiseFailedJobEvent() 之前执行 failed() 会阻止此事件发生。
UPDATE:
更新:
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:
问题似乎源于我如何使它失败。如果我故意破坏作业队列表中的数据,则 failed() 方法永远不会被调用。日志中有堆栈跟踪:
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(8, 'unserialize():
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?
如果我真的进入 vendor/laravel/framework/src/Illuminate/Queue/Worker.php 并在每次运行时强制它失败(当然是以无异常的方式),然后 failure() 被调用。显然,问题是我怎么知道这个队列在现实世界的故障中会如何表现?如果损坏的 db 数据导致失败但阻止了 failure() 被调用,这是不好的。如果现实世界中的 db 队列数据真的损坏了怎么办?
回答by ShaunUK
Try this out from my conversation with Graham at https://github.com/laravel/framework/issues/9799
从我在https://github.com/laravel/framework/issues/9799与 Graham 的对话中试试这个
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.
最后,我能找到的最优雅的解决方案是将 failed() 方法在作业类本身上触发,是将以下内容添加到 EventServiceProvider.php 的 boot() 方法中。捕获触发的完整失败事件,然后挖掘命令/作业并将其反序列化以调用 failed() 方法。
Queue::failing(function($connection, $job, $data)
{
$command = (unserialize($data['data']['command']));
$command->failed();
});
回答by aethergy
If you start the queue listener like this
如果你像这样启动队列监听器
nohup php artisan queue:listen > storage/logs/queue.log 2>&1 &
then a queue log file will be created and populated automatically.
然后将创建并自动填充队列日志文件。