当我使用queue:listen

时间:2019-05-22 14:15:28

标签: php laravel docker laravel-5

我的Laravel队列有问题。它将开始处理作业,但随后挂在中间的某个位置(基于对日志的自定义回显),并且仅以超时结束。问题在于该作业不应超过1分钟,但是队列中的作业可以运行10分钟以上,没有任何结果也没有任何错误-除了标准超时错误外。

工作

应该在队列中处理的作业包含标准的Eloquent选择和一个更新方法,该更新方法应该更新另一个模型的属性。

// app\Listeners\CountReceivedTextAnswers

// There follows the listener's handle method. Nothing else is inside the 
// Listener, it also implements ShouldQueue interface and InteractsWithQueue trait.
public function handle($event)
{
    $questions = $this->question->whereTarget(['gl', 'povinn', 'ucit'], $event->evaluation->id, 'text');

    $this->evaluation->updateOptions(
        $event->evaluation->id,
        'number_of_answers_to_text_questions',
        $this->answer->countAnswersToManyQuestions($questions)
    );
}


// app\Repositories\Answers\AnswersEloquentRepository

// This is the method that is called inside the listener. It passes 
// collection of questions to the following method which should count
// answers on them.
public function countAnswersToManyQuestions(Collection $questions): int
{
    $result = 0;

    foreach ($questions as $question) {
        $result += $this->countAnswersToQuestion($question);
    }

    return $result;
}

// This is the count method, it accepts Question model and count 
// number of answers received on that question.
public function countAnswersToQuestion(Question $question): int
{
    $select = [
        'id',
        'import_id',
        'question_id',
        'content',
        'value',
        'hidden',
        'hidden_by',
        'signed_by',
    ];

    return Answer::select($select)
        ->whereDoesntHave('answered')
        ->where('question_id', '=', $question->id)
        // Remove unwanted answers e.g. empty.
        ->when($question->form === 'text', function (Builder $query) {
            $query->whereNotNull('content');
        })
        ->when($question->form === 'slider', function (Builder $query) {
            $query->whereNotNull('value');
        })
        ->count();
}


// app\Repositories\Evaluation\EvaluationEloquentRepository

// This is the update method that is called to update the value 
// inside the listener.
public function updateOptions($id, $field, $value)
{
    $evaluation = $this->find($id);

    $options = json_decode($evaluation->options, true);
    $options[$field] = $value;

    return $this->update($id, [
        'options' => $options
    ]);
}

当我在Tinker中从侦听器手动调用相同的方法时,大约需要30秒才能完成。因此,我认为问题不应该与方法本身有关,而可能与配置有关?

我的设置

我正在使用具有五个容器的docker,其中两个基于我的docker image.dockerfile),该容器基于官方的php:7.3-fpm映像,并安装了oci8和一些其他扩展名。容器的启动脚本基于此tutorial,因此我可以同时使用一个容器-队列和应用程序。其余的容器基于其官方docker映像-httpd:2.4-alpine,mysql:8.0和redis:5-alpine。我还应该注意,我正在使用 Laravel 5.5

php.ini

这些值我在php.ini配置中更改。休息应该是默认的。设置它是相当慷慨的,因为起初我认为该错误与php config有关,但是似乎没有,因为php的错误日志中没有错误。

date.timezone=UTC
display_errors=on
log_errors=On
error_log=/var/www/storage/logs/php.log

opcache.enable=1
opcache.enable_cli=1

memory_limit = 512M
upload_max_filesize = 128M
post_max_size = 64M
max_execution_time=900
max_input_time=900
default_socket_timeout=60

starth.sh

#!/usr/bin/env bash

set -e

role=${CONTAINER_ROLE:-app}
env=${APP_ENV:-production}

if [[ "$env" != "local" ]]; then
    echo "Caching configuration..."
    (cd /var/www && php artisan config:cache && php artisan route:cache && php artisan view:cache)
fi

if [[ "$role" = "app" ]]; then

    exec php-fpm

elif [[ "$role" = "queue" ]]; then

    echo "Running the queue..."
    php /var/www/artisan queue:listen --verbose --tries=10 --sleep=0 --timeout=800 --memory=512

elif [[ "$role" = "scheduler" ]]; then

    while [[ true ]]
    do
      php /var/www/artisan schedule:run --verbose --no-interaction &
      sleep 60
    done

else
    echo "Could not match the container role \"$role\""
    exit 1
fi


唯一的错误

有一个唯一的错误,我可以在laravel.log中找到,但是我不认为实际的问题出在工作的长度上,因为在Tinker中运行它所花费的时间比超时要少得多。设置为。

  

[2019-05-22 16:06:39] local.ERROR:进程“'/ usr / local / bin / php''artisan'队列:工作'redis'--once --queue ='default '--delay = 0 --memory = 512 --sleep = 0 --tries = 10“超过了800秒的超时时间。 {“例外”:“ [对象](Symfony \ Component \ Process \ Exception \ ProcessTimedOutException(代码:0):进程\“'/ usr / local / bin / php''artisan'队列:work'redis'-在--var / www / vendor / symfony / process / Process中,一次--queue ='default'--delay = 0 --memory = 512 --sleep = 0 --tries = 10 \“超过了800秒的超时时间。 .php:1335)   [堆栈跟踪]   /var/www/vendor/symfony/process/Process.php(424):Symfony \ Component \ Process \ Process-> checkTimeout()   /var/www/vendor/symfony/process/Process.php(212):Symfony \ Component \ Process \ Process-> wait()   /var/www/vendor/laravel/framework/src/Illuminate/Queue/Listener.php(193):Symfony\Component\Process\Process->run(Object(Closure))   /var/www/vendor/laravel/framework/src/Illuminate/Queue/Listener.php(115):Illuminate\Queue\Listener->runProcess(Object(Symfony\Component\Process\Process),'512')   /var/www/vendor/laravel/framework/src/Illuminate/Queue/Console/ListenCommand.php(68):Illuminate \ Queue \ Listener-> listen('redis','default',Object(Illuminate \ Queue \ ListenerOptions ))   [内部功能]:Illuminate \ Queue \ Console \ ListenCommand-> handle()   /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(29):call_user_func_array(Array,Array)   /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(87):Illuminate \ Container \ BoundMethod :: Illuminate \ Container \ {closure}()   /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31):Illuminate \ Container \ BoundMethod :: callBoundMethod(Object(Illuminate \ Foundation \ Application),Array,Object(Closure))   /var/www/vendor/laravel/framework/src/Illuminate/Container/Container.php(549):Illuminate \ Container \ BoundMethod :: call(Object(Illuminate \ Foundation \ Application),Array,Array,NULL)   /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(183):Illuminate\Container\Container->call(Array)   /var/www/vendor/symfony/console/Command/Command.php(255):Illuminate \ Console \ Command-> execute(对象(Symfony \ Component \ Console \ Input \ ArgvInput),对象(Illuminate \ Console \ OutputStyle) )   /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(170):Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput),对象(Illuminate \ Console \ OutputStyle)   /var/www/vendor/symfony/console/Application.php(960):照亮\控制台\命令->运行(对象(Symfony \组件\控制台\输入\ ArgvInput),对象(Symfony \组件\控制台\输出\ ConsoleOutput))   /var/www/vendor/symfony/console/Application.php(255):Symfony \ Component \ Console \ Application-> doRunCommand(Object(Illuminate \ Queue \ Console \ ListenCommand),Object(Symfony \ Component \ Console \ Input \ ArgvInput),对象(Symfony \ Component \ Console \ Output \ ConsoleOutput))   /var/www/vendor/symfony/console/Application.php(148):Symfony \ Component \ Console \ Application-> doRun(Object(Symfony \ Component \ Console \ Input \ ArgvInput),Object(Symfony \ Component \ Console \输出\控制台输出))   /var/www/vendor/laravel/framework/src/Illuminate/Console/Application.php(88):Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput),Object( Symfony \ Component \ Console \ Output \ ConsoleOutput))   /var/www/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(121):Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput),Object( Symfony \ Component \ Console \ Output \ ConsoleOutput))   / var / www / artisan(35):照亮\ Foundation \ Console \ Kernel-> handle(Object(Symfony \ Component \ Console \ Input \ ArgvInput),Object(Symfony \ Component \ Console \ Output \ ConsoleOutput))   {主要}   “}


我尝试了在互联网上找到的所有可能的建议,更改了php artisan queue:listen命令和php.ini中的所有值,但始终以相同的结果结尾。我也尝试定位redis日志,但是没有成功,因此我将队列移到了数据库,结果总是一样。队列侦听器开始了这项工作,但是随后挂起,没有任何其他信息或错误。 我还应该说,拥有所有这些监听器和工作的工作人员在docker映像之外的工作情况非常好。

我将非常感谢您的任何建议或建议!另外,如果您想了解更多信息,请告诉我,我会添加它们。

2 个答案:

答案 0 :(得分:0)

您可以在storage / logs / laravel.log中检查您的日志, 也许错误在那里

答案 1 :(得分:0)

最后,我发现队列工作程序确实超出了超时时间。这是由于以下事实:在某些数据迁移期间,所有外键和索引都被删除,因此从表中加载关系花费的时间太长。重新定义数据库中的关系使队列工作器明显更快,错误消失了。