Очередь Laravel показывает слишком много попыток и превышено максимальное время ожидания 60 секунд, но задание успешно выполнено

(Примечание: я новичок в использовании AWS SQS для очередей). У меня есть функция, в которой я хотел бы вставить десятки тысяч записей в Excel, сохранить Excel в AWS S3 и отобразить в таблице данных внешнего интерфейса. Эта функция выполняется с использованием очереди AWS SQS с супервизором в качестве рабочего в веб-приложении Laravel 9.

Ошибка, которую я получаю:

  1. Job\SomeJob выполнялся слишком много раз или выполнялся слишком долго. задание могло быть ранее тайм-аут. {"исключение":"[объект] (Illuminate\Queue\MaxAttemptsExceededException (код: 0)
  1. (Symfony\Component\ErrorHandler\Error\FatalError(код: 0): максимум время выполнения 60 секунд превышено в /var/app/current/vendor/laravel/framework/src/Illuminate/Collections/Arr.php:314)

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

Что я пробовал, так это Log::info() каждую строку до и после процесса, чтобы узнать, что вызывает ошибку.

Моя настройка Supervisor для SQS:

[program:sqs-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/app/current/artisan queue:work sqs --sleep=3 --tries=1 --timeout=1800
autostart=true
autorestart=true
user=webapp
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/html/worker.log

Как я отправляю работу:

class SomeOtherController extends Controller{
   public function show(){
      dispatch(new SomeJob($id));

      return 'job run';
   }
}

Содержание работы такое:

Class SomeJob implements ShouldQueue{

   use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

   public $timeout = 1800;
  
   public $id;
   public function __construct($id){
      $this->id = $id;
   }

   public function handle(){
      Log::info('start job');

      $apps = Application::where('client_id', $id)->get(); //15000+ records

      Log::info('start foreach');

      $count = 0; //to count each 100 records, do Log::info()
      foreach($apps as $key => $app){
         if ($count == 100){
            Log::info('This is the '.$key.' record');
            $count = 0;
         }

         //the actual job is much more lenghty and complicated
         $list = new ApplicationTable();

         $list->client_id = $app->client_id;
         $list->name = $app->name;
         $list->booking = $app->booking->name;
         $list->price = $app->price + $app->discount + $app->gst;
         $list->save();
         $count++;
      }
      Log::info('end foreach');
      //Some process to generate and store excel to S3
      $lists = ApplicationTable::where('client_id','=',$id)->get();
    
      (new ReportExport($lists))->store('application_report');

      $s3 = Storage::disk('s3');
    
      $s3_path =  'ApplicationReport';
      $s3->put($s3_path, file_get_contents('application_report'));

      //unlink
      unlink($path);

      $user_email = $apps->first()->user->email;
      if (isset($user_email)){
        \Mail::to($user_email)->send(new ApplicationReportMail($id));
      }
      log::info('end job');
      return true;
   }
}

Я ожидаю, что в журнале будут отображаться все процессы и заканчиваться «завершением задания» без каких-либо ошибок. Но что я получаю:

[20XX-XX-XX 12:56:34] start job
[20XX-XX-XX 12:56:36] start foreach
[20XX-XX-XX 12:56:41] This is the 100 record
[20XX-XX-XX 12:56:47] This is the 200 record
[20XX-XX-XX 12:56:52] This is the 300 record
[20XX-XX-XX 12:56:57] This is the 400 record
[20XX-XX-XX 12:57:04] local.ERROR: App\Jobs\SomeJob has been attempted too many times or run too long. The job may have previously timed out. {"exception":"[object] (Illuminate\\Queue\\MaxAttemptsExceededException(code: 0): App\\Jobs\\SomeJob has been attempted too many times or run too long. The job may have previously timed out. at /var/app/current/vendor/laravel/framework/src/Illuminate/Queue/Worker.php:746)"
[20XX-XX-XX 12:57:06] This is the 500 record
[20XX-XX-XX 12:57:10] This is the 600 record
...
[20XX-XX-XX 13:09:46] This is the 11400 record
[20XX-XX-XX 13:09:52] This is the 11500 record
[20XX-XX-XX 13:09:53] Maximum execution time of 60 seconds exceeded {"userId":144,"exception":"[object] (Symfony\\Component\\ErrorHandler\\Error\\FatalError(code: 0): Maximum execution time of 60 seconds exceeded at /var/app/current/vendor/laravel/framework/src/Illuminate/Collections/Arr.php:314)"
[20XX-XX-XX 13:16:20] local.INFO: end foreach
[20XX-XX-XX 13:16:23] local.INFO: end job

Как видно из журналов, задание выполнялось, и примерно через 30-60 секунд Laravel выдает исключение MaxAttemptsExceededException. Затем в 13:09:53 получите еще одно исключение FatalError, в котором говорится, что превышено время ожидания 60 секунд, и журнал остановлен. Он продолжается после 13:16:20, чтобы завершить процесс...

Для всех, кому интересно, какая конфигурация для очереди внутри таблицы failed_jobs:

...,"maxTries":null,"maxExceptions":null,"failOnTimeout":false,"backoff":null,"timeout":1800,"retryUntil":null,...

Очень признателен за любой вклад и разъяснения по этому вопросу. У меня есть поиск решения, но безуспешно.

Задания Laravel имеют максимальное количество попыток и/или максимальное время повтора, Laravel docs для получения дополнительной информации.

geertjanknapen 02.02.2023 09:07

Да, у Laravel Jobs есть максимальная попытка и максимальное время повторной попытки. Но для своей конфигурации я не указывал, и не уверен, есть для этого дефолт или нет. В любом случае, я получаю это исключение, но задание все еще выполняется до завершения. Это не остановилось. См. представленные журналы. Вот в этом вопросе я не знаю.

Nazhan Nasir 02.02.2023 10:09

Возможно, этот ответ поможет: stackoverflow.com/a/34487604/9636400

geertjanknapen 02.02.2023 11:23

Спасибо за ответ @geertjanknapen, но после поиска «retry_after» и прослушивания объяснения retry_after эта конфигурация предназначена для тех случаев, когда задание laravel не завершилось неудачно или успешно через 60 секунд, а затем повторите задание. Однако в моем случае это задание фактически обрабатывается, и его выполнение заняло около 20 минут. Таким образом, исключение 60 секунд на самом деле является ложным отрицательным результатом. Как запретить laravel проверять статус задания через 60 секунд для этого конкретного задания, не затрагивая другие задания?

Nazhan Nasir 03.02.2023 09:35

Я думаю, что вы сталкиваетесь с timeout (сбой задания через x секунд), но вы хотите, чтобы это влияло только на это конкретное задание. Так что на работе вы могли бы сделать public $timeout = 500;, где 500 — это время в секундах. (500 = 3 минуты, 1200 = 20 минут).

geertjanknapen 03.02.2023 11:30

Я пытался использовать public $timeout = 1800; = 30 минут в задании, но иногда после 2 минут обработки я получаю ошибку тайм-аута 60 секунд. Что тоже неправильно, потому что 2 минуты уже прошли как 60 секунд. Это очень расстраивает и сбивает с толку.

Nazhan Nasir 07.02.2023 08:41

Можете ли вы обновить вопрос с кодом для полного задания и с тем, как вы выполняете эти задания? (app\Console\Kernel.php:schedule())

geertjanknapen 07.02.2023 09:08

Я не использую расписание ядра, но вызываю метод dispatch(new SomeJob($id)); для выполнения задания.

Nazhan Nasir 07.02.2023 09:30

Пожалуйста, поделитесь своими настройками конфигурации Supervisor . Кроме того, ваша работа имеет характеристики по умолчанию (use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;) и не реализует интерфейс ShouldQueue. Пожалуйста, обратитесь к Создание классов работы

steven7mwesigwa 07.02.2023 09:56

Я включил конфигурацию своего супервайзера и черты для работы.

Nazhan Nasir 07.02.2023 10:19

@NazhanNasir У вас все еще возникают проблемы после добавления необходимых черт и внедрения интерфейса ShouldQueue в вашу работу?

steven7mwesigwa 07.02.2023 10:21

@steven7mwesigwa Да, по-прежнему возникают проблемы (ложноотрицательные ошибки), если задание выполняется более 2 минут.

Nazhan Nasir 07.02.2023 10:31

Отвечает ли это на ваш вопрос? Фатальная ошибка: Превышено максимальное время выполнения 30 секунд

steven7mwesigwa 07.02.2023 10:40

Я только что начал задание в [2023-02-07 17:50:57] и получил это после добавления set_time_limit(1800);: [2023-02-07 17:51:29] local.ERROR: App\Jobs\SomeJob has been attempted too many times or run too long. The job may have previously timed out. {"exception":"[object] (Illuminate\\Queue\\MaxAttemptsExceededException(code: 0)..." Я получаю это сейчас, но задание все еще обрабатывается и закончилось в [2023-02-07 17:53:35] local.INFO: end job

Nazhan Nasir 07.02.2023 10:54

На основании Истечения срока действия и времени ожидания и Задание выполнялось слишком много раз или выполнялось слишком долго, вам необходимо увеличить значение retry_after до максимального количества секунд, которое разумно требуется вашим заданиям для завершения обработки.

steven7mwesigwa 07.02.2023 11:35

Amazon SQS повторит задание на основе Тайм-аута видимости по умолчанию, который управляется в консоли AWS. К сожалению, у меня нет опыта работы с SQS, чтобы помочь вам увеличить «Время ожидания видимости по умолчанию». Наконец, убедитесь, что вы действительно используете правильное соединение с очередью, проверив, установлен ли QUEUE_CONNECTION=sqs в вашем файле .env.

steven7mwesigwa 07.02.2023 11:40

@steven7mwesigwa Тайм-аут видимости по умолчанию для SQS сработал! Мой SQS был установлен на 30 секунд, поэтому каждые 120 секунд (4 повторения) laravel отправляет ошибку MaxAttemptsExceededException. Я перешел на 1800 и больше не вижу ошибки. Большое спасибо! Вы можете отправить свой ответ, чтобы я мог отметить его как решение.

Nazhan Nasir 07.02.2023 12:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
17
102
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  1. (Symfony\Component\ErrorHandler\Error\FatalError(код: 0): максимум время выполнения 60 секунд превышено в /var/app/current/vendor/laravel/framework/src/Illuminate/Collections/Arr.php:314)

Во-первых, что касается вышеуказанной ошибки, вам необходимо увеличить конфигурацию PHP «максимальное время выполнения».

Фатальная ошибка: Превышено максимальное время выполнения 30 секунд

Это можно решить, добавив set_time_limit(1800); в начало тела метода SomeJob::handle(...) задания.


  1. Job\SomeJob выполнялся слишком много раз или выполнялся слишком долго. задание могло быть ранее тайм-аут. {"исключение":"[объект] (Illuminate\Queue\MaxAttemptsExceededException (код: 0)

Во-вторых, что касается вышеуказанной ошибки,

На основании Истечения срока действия и времени ожидания и Задание выполнялось слишком много раз или выполнялось слишком долго, вам необходимо увеличить значение retry_after до максимального количества секунд, которое разумно требуется вашим заданиям для завершения обработки.

Amazon SQS повторит задание на основе Тайм-аута видимости по умолчанию, который управляется в консоли AWS. Время ожидания видимости сообщения по умолчанию составляет 30 секунд. Минимум 0 секунд. Максимум 12 часов.

Увеличение значения «Тайм-аут видимости Amazon SQS по умолчанию» до более высокого значения на пару секунд больше, чем ваша конфигурация тайм-аута очереди, должна решить эту проблему. Если ваш параметр --timeout длиннее вашего retry_after или значения конфигурации «Тайм-аут видимости Amazon SQS по умолчанию», ваши задания могут быть обработаны дважды.

См.: Настройка параметров очереди (консоль) для получения информации о настройке «тайм-аута видимости Amazon SQS» для очереди с помощью консоли.


Наконец, убедитесь, что вы действительно используете правильное соединение с очередью, проверив, установлен ли QUEUE_CONNECTION=sqs в вашем файле .env.

Примечание для других, столкнувшихся с той же проблемой: если вы установите для параметра супервизора значение 1800 секунд, то время ожидания видимости по умолчанию в SQS также должно быть равно 1800 секундам.

Nazhan Nasir 08.02.2023 02:08

Другие вопросы по теме