Работа очереди Laravel никогда не заканчивается только тайм-аутом, когда я использую очередь: listen - PullRequest
0 голосов
/ 22 мая 2019

У меня проблема с очередью 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 секунд. Таким образом, я полагаю, что проблема должна быть связана не с самим методом, а с чем-то другим, возможно, с конфигурацией?

Моя настройка

Я использую докер с пятью контейнерами, два из них основаны на моем образе докера ( .dockerfile ), который основан на официальном образе php: 7.3-fpm с установленным oci8 и несколько других расширений. Скрипт запуска контейнера основан на этом учебном пособии , поэтому я могу использовать один контейнер как для очереди, так и для приложения. Остальные контейнеры основаны на их официальных образах докеров - httpd: 2.4-alpine, mysql: 8.0 и redis: 5-alpine. Следует также отметить, что я использую Laravel 5.5

php.ini

Эти значения я изменяю в конфигурации php.ini. Отдых должен быть по умолчанию. Он довольно щедрый, потому что сначала я думал, что ошибка связана с конфигурацией 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

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' queue: work 'redis' --once --queue = 'default '--delay = 0 --memory = 512 --sleep = 0 --tries = 10 "превысил тайм-аут 800 секунд. {"исключение": "[объект] (Symfony \ Component \ Process \ Exception \ ProcessTimedOutException (код: 0): процесс \" '/ usr / local / bin / php' 'ремесленник' очередь: работа 'redis' - один раз --queue = 'default' --delay = 0 --memory = 512 --sleep = 0 --tries = 10 \ "превысил тайм-аут на 800 секунд. at / var / www / vendor / symfony / process / Process .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): Подсветка \ Queue \ Listener-> runProcess (Объект (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 )) [внутренняя функция]: Подсветка \ 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): Подсветка \ Container \ BoundMethod :: Подсветка \ Container \ {closure} () /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31): Illuminate \ Container \ BoundMethod :: callBoundMethod (Объект (Освещать \ Фонд \ Приложение), Массив, Объект (Закрытие)) /var/www/vendor/laravel/framework/src/Illuminate/Container/Container.php(549): Подсветка \ Container \ BoundMethod :: call (Объект (Подсветка \ Фонд \ Приложение), Массив, Массив, NULL)/var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(183): подсветить \ Container \ Container-> call (Array) /var/www/vendor/symfony/console/Command/Command.php(255): Illuminate \ Console \ Command-> execute (Object (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), Объект (Осветите \ Console \ OutputStyle)) /var/www/vendor/symfony/console/Application.php(960): Подсветка \ Console \ Command-> run (Объект (Symfony \ Component \ Console \ Input \ ArgvInput), Объект (Symfony \ Component \ Console \ Output \) ConsoleOutput)) /var/www/vendor/symfony/console/Application.php(255): Symfony \ Component \ Console \ Application-> doRunCommand (Object (Illuminate \ Queue \ Console \ ListenCommand), Объект (Symfony \ Component \ Console \ Input \ ArgvInput), Object (Symfony \ Component \ Console \ Output \ ConsoleOutput)) /var/www/vendor/symfony/console/Application.php(148): Symfony \ Component \ Console \ Application-> doRun (Объект (Symfony \ Component \ Console \ Input \ ArgvInput), Объект (Symfony \ Component \ Console \) Выход \ ConsoleOutput)) /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): Осветить \ Console \ Application-> run (Object (Symfony \ Component \ Console \ Input \ ArgvInput), Object ( Symfony \ Component \ Console \ Output \ ConsoleOutput)) / var / www / artisan (35): подсветить дескриптор \ Foundation \ Console \ Kernel-> (объект (Symfony \ Component \ Console \ Input \ ArgvInput), объект (Symfony \ Component \ Console \ Output \ ConsoleOutput)) {главный} "}


Я испробовал, вероятно, все возможные советы, которые нашел в Интернете, я изменил все значения в команде php artisan queue:listen, а также в php.ini, но это всегда заканчивается одним и тем же результатом. Я также попытался найти журнал Redis, но безуспешно, поэтому я переместил очередь в базу данных, и результат всегда был одинаковым. Слушатель очереди запустил задание, но затем как-то завис, без какой-либо дополнительной информации или ошибки. Я также должен сказать, что работник со всеми этими слушателями и заданиями очень хорошо работает вне образов докеров.

Буду очень признателен за любой совет или совет! Также, если вы хотите увидеть больше информации, пожалуйста, дайте мне знать, я добавлю их.

Ответы [ 2 ]

0 голосов
/ 18 июня 2019

В конце концов я обнаружил, что работник очереди действительно превысил время ожидания.Это было связано с тем, что во время некоторой миграции данных были удалены все внешние ключи и индексы, поэтому загрузка отношений из таблиц заняла слишком много времени.Переопределение отношений в БД сделало работника очереди значительно быстрее и ошибка исчезла.

0 голосов
/ 22 мая 2019

Вы можете проверить свой журнал, в хранилище / logs / laravel.log, Может быть, ошибка могла быть там

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...