提问者:小点点

当我使用queue:listen时,Laravel队列作业永远不会以超时结束


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

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

// 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映像(.dockerfile),它基于官方的php:7.3-fpm映像,并安装了oci8和其他一些扩展。容器的启动脚本基于本教程,因此我可以同时使用一个容器—队列和应用程序。其余的容器基于它们的官方docker图像——httpd:2.4-alpine、mysql:8.0和redis:5-alpine。我还应该注意,我使用的是Laravel5.5

php.ini

我在php中更改这些值。ini配置。Rest应该是默认值。这是一个非常慷慨的设置,因为起初我认为错误与php配置有关,但似乎不是,因为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

开始。嘘

#!/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]本地的。错误:进程'/usr/local/bin/php''artisan'队列:work'redis'--once--队列='默认'--延迟=0--内存=512--睡眠=0--尝试=10'超过了800秒的超时时间。{"异常":"[对象](Symfony\Component\ProcessTimedOutExcture(代码:0):进程\"'/usr/local/bin/php''artisan'队列:work'redis'--once--队列='默认'--延迟=0--内存=512--睡眠=0--尝试=10\"超过了800秒的超时。 /var/www/vendor/symfony/process/P


我尝试了可能在互联网上找到的所有可能的建议,我更改了php artisan队列:listen命令和php中的所有值。ini但它总是以相同的结果结束。我还试图找到redis日志,但没有成功,因此我将队列移动到数据库,结果总是一样的。队列侦听器启动了作业,但随后不知何故挂起,没有任何进一步的信息或错误。我还应该说,有这么多听众和工作的工人在docker形象之外工作得很好。

我将非常感谢任何建议或提示!另外,如果您想查看更多信息,请让我知道,我会添加它们。


共2个答案

匿名用户

最后,我发现队列工作者确实超过了超时时间。这是因为在某些数据迁移过程中,删除了所有外键和索引,因此从表中加载关系花费的时间太长。重新定义数据库中的关系使队列工作程序大大加快,错误消失。

匿名用户

你可以检查你的日志,在存储/日志/laravel.log,也许错误可能在那里