Статьи

IronMQ и Laravel: задержки и повторные попытки

Ранее мы видели, как использовать очереди push-уведомлений Iron с Laravel. Все, что нам нужно было сделать, это настроить учетную запись Iron, добавить URL-адрес подписчика, отправить сообщение в очередь и получить сообщение.

Способ, которым Laravel поддерживает готовые очереди Iron, удивителен, но всегда есть ограничения. В этой статье мы сосредоточимся на этих ограничениях и научимся их решать.

Сценарии

Есть три возможных сценария:

  1. Вы получили сообщение и успешно завершили работу.

    • Вам нужно указать, чтобы Iron сообщил, что задание было успешно выполнено, и ему нужно удалить его из очереди.
  2. Вы получили сообщение и что-то пошло не так. По сути, ваша работа не была успешной.

    • В этом случае мы должны сообщить Iron, что мы потерпели неудачу, и он должен повторить попытку, или если вы ничего не можете сказать Iron, это должно быть достаточно умно, чтобы повторить задание, т. Е. Через некоторое время снова отправить то же сообщение вашему подписчику.
  3. Вы получили сообщение, но ваша работа — длительный процесс (который занимает больше минуты)

    • Железо должно ждать дольше, прежде чем оно отправит сообщение.

Это все практические сценарии, и вы будете сталкиваться с ними ежедневно. И да, вам нужно охватить эти случаи в ваших приложениях.

Можно использовать Iron на полную мощность, если использовать PHP-библиотеку Iron MQ. Во время установки мы включили "iron-io/iron_mq": "1.4.6" Код для того же самого размещен в https://github.com/iron-io/iron_mq_php Давайте взглянем на документацию и попытаемся понять, как использовать эту библиотеку.

Мы инициируем очередь следующим образом:

 $ironmq = new IronMQ(array(
        "token" => 'XXXXXXXXX',
        "project_id" => 'XXXXXXXXX'
    ));

И вот как мы публикуем в очереди:

 $ironmq->postMessage($queue_name, "Test Message", array(
        'timeout' => 120,
        'delay' => 2,
        'expires_in' => 2*24*3600 # 2 days
    ));

Чтобы превратить очередь в push-очередь (или создать ее), все, что нам нужно сделать, это опубликовать в очереди такие параметры, как список подписчиков, push_type и т. Д. Используя библиотеку, вы можете сделать следующее:

Примечание. Если в очереди нет подписчиков, это очередь извлечения.

 $params = array(
        "push_type" => "multicast",
        "retries" => 5,
        "subscribers" => array(
            array("url" => "http://your.first.cool.endpoint.com/push"),
            array("url" => "http://your.second.cool.endpoint.com/push")
        )
    );
    
    $ironmq->updateQueue($queue_name, $params);

Это оно!

Это именно то, что делает Laravel, когда вы запускаете команду artisan queue:subscribe Напомним, что после того, как вы выполните необходимую настройку в файле queue.php(заполнив его значениями project_id, token и queue_name) , вы запускаете команду для регистрации ваших подписчиков:

 php artisan queue:subscribe queue_name http://foo.com/queue/receive

Эта команда запускает следующий код:

/vendor/laravel/framework/src/Illuminate/Queue/Console/SubscribeCommand.php

 public function fire()
    {
		$iron->getIron()->updateQueue($this->argument('queue'), $this->getQueueOptions());
	}

Некоторый контент исключен из файла для краткости.

Вот как Laravel преобразует нашу очередь в очередь push. Это то же самое, что и при использовании библиотеки Iron MQ.

Использование PHP-библиотеки Iron MQ

  1. Создать новый контроллер IronController в приложении / контроллеры

     <?php
            
            class IronController extends Controller {
            
                protected $ironmq;
    
            	public function __construct()
            	{
            		$this->ironmq = new IronMQ(array(
            					    "token" => 'XXXXXXXXXXXXXXXXXXX', //Your token from dashboard
            					    "project_id" => 'XXXXXXXXXXXXXXX' //Your project ID from dashboard
            					));
            	}
            
            }

    Приложение / контроллер / IronController.php

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

     Route::get('iron/create','IronController@create'); //Create a Queue and add subscribers
            Route::get('iron/push','IronController@push'); //Push a message to Queue
            Route::get('iron/status/{id}','IronController@status'); //Know the status of the message we pushed
            Route::post('iron/receive','IronController@receive'); //Receive the message and process it

    Приложение / routes.php

  3. Теперь давайте напишем метод для создания очереди с подписчиком

     public function create()
        	{
        		$params = array(
        		    "subscribers" => array(
        		        array("url" => url('iron/receive'))
        		    )
        		);
        
        		$this->ironmq->updateQueue('testing', $params);
        
        		return 'Push Queue Created';
        	}

    Приложение / контроллер / IronController.php

  4. Вам нужно посетить http://953ffbb.ngrok.com/iron/create/iron/create Примечание. Ваш URL-адрес ngrok будет другим.

    На этом этапе вы можете перейти к Iron DashBoard -> MQ -> Queues -> Найти очередь с именем ‘testing’ -> Push Queues и убедиться, что ваш подписчик указан там аналогично http://953ffbb.ngrok.com/iron/receive

  5. Давайте добавим методы, чтобы отправить сообщение в очередь и проверить статус.

    Способ отправить сообщение:

     public function push()
            {
            	//Just some data you want to pass
            	$data = array(
            		'first_name' => 'Rajiv', 
            		'last_name'  => 'Seelam'
            	);
            
            	//Convert data into a string so that we can pass it
            	$data = serialize($data);
            
            	//Post the message
            	$job = $this->ironmq->postMessage('testing', $data);
            
            	Log::info(__METHOD__.' - Message pushed with job_id : '.$job->id);
            
                return Redirect::to('iron/status/'.$job->id);
            }

    Способ проверки статуса сообщения:

     public function status($id)
    	{
    	$status = $this->ironmq->getMessagePushStatuses('testing',$id);
    	dd($status);
    	}

    Приложение / контроллер / IronController.php

  6. Нам нужен метод для получения сообщения, когда мы нажимаем.

     public function receive()
            {
            	$req = Request::instance();
        
        		$jobId = $req->header('iron-message-id'); //Get job id 
        
        		$data = unserialize($req->getContent()); //Get content and unserialize it
        
        		Log::info(__METHOD__.' - Job Received From Iron with Job ID : '.$jobId);
        
        		return Response::json(array(),200);
        	}

    Приложение / контроллер / IronController.php

На этом этапе вы должны понимать, что это метод, который будет получать сообщение, потому что в методе createurl('iron/receive')

Держите ваше приложение / storage / logs / laravel.log открытым, чтобы увидеть, что происходит.

Теперь, если вы посетите http://953ffbb.ngrok.com/iron/push

 array (size=1)
          0 => 
            object(stdClass)[184]
              public 'retries_delay' => int 60
              public 'retries_remaining' => int 3
              public 'retries_total' => int 3
              public 'status_code' => int 200
              public 'status' => string 'deleted' (length=7)
              public 'url' => string 'http://953ffbb.ngrok.com/iron/receive' (length=38)
              public 'id' => string '6019569765635787179' (length=19)

И ваши журналы должны быть похожи на:

 [2014-05-31 12:45:04] production.INFO: IronController::push - Message pushed with job_id : 6019569765635787179 [] []
[2014-05-31 12:45:05] production.INFO: IronController::receive - Job Received From Iron with Job ID : 6019569765635787179 [] []

приложение / хранение / журналы / laravel.log

Эти журналы подтверждают нашу активность. Давайте подведем итоги того, что мы сделали здесь:

  • Мы отправили сообщение в очередь под названием «тестирование»
  • Затем мы проверили статус сообщения в очереди
  • Мы получили сообщение и что-то записали.

Задержки и повторные попытки

Теперь давайте пойдем немного глубже. Откройте панель управления Iron и перейдите на страницу очередей (щелкните MQ) -> Откройте очередь тестирования и выберите «Push Queues», вы увидите список подписчиков, а в «Push Information» вы увидите «Retries» и «Retries Delay». ».

Что это значит?

Retries : по умолчанию установлено значение 3, что означает, что Iron будет повторять сообщение 3 раза.

Задержка повторных попыток : значение по умолчанию равно 60, что означает, что Iron по умолчанию снова отправит сообщение подписчикам через 60 секунд, если сочтет, что сообщение не было успешно обработано.

Когда Iron повторяет сообщение? :

  1. Когда он не получает ответ от вашего приложения:

    • Ваше приложение не может дать ответ из-за какой-то ошибки.
    • Ваше приложение все еще обрабатывает задание, длительный процесс.
  2. Когда он получает ошибку в ответе:

    • Ваше приложение ответило с ошибкой 4xx или 5xx.
  3. Когда вы отправляете ответ 202:

    • Вы просите Айрон повторно отправить сообщение после задержки.

Если вы проверите вывод статуса (см. Выше), вы увидите следующую строку:

 public 'status' => string 'deleted'

Так мы узнаем статус сообщения, которое мы нажали. Возможные значения для статуса (в настоящее время):

  1. повторная попытка — задание будет отправлено конечной точке, т. е. подписчику ( столько раз, сколько установлено «Повторные попытки» ).
  2. удалено — задание удалено.
  3. зарезервировано — задание будет повторено после истечения времени ожидания.
  4. ошибка — произошла ошибка и больше ничего не будет сделано.

Вы должны отправить 200 ответ, чтобы удалить сообщение.

Следует помнить, что Iron будет повторять сообщение после истечения времени ожидания, если оно не получит ответ (оно будет повторяться после истечения времени ожидания столько раз, сколько указано в ‘retries_total’).

Можем ли мы изменить эти параметры? Конечно!

При публикации сообщения вы можете указать время ожидания (для выполнения длительных заданий может потребоваться больше минуты)

 $this->ironmq->postMessages('testing', "data", array(
        "timeout" => 300 // Wait for 300 seconds = 5 minutes
    ));

Если вы хотите уменьшить или увеличить количество повторных попыток, вам нужно вызвать метод updateQueue.

 $params = array(
	    "retries" => 5
	);

	$this->ironmq->updateQueue('testing', $params);

Можем ли мы изменить статус сообщения, которое находится в очереди? Конечно! Вот как вы должны использовать очереди, и на самом деле вы уже делаете это.

Давайте посмотрим, как мы можем изменить статус сообщения:

  1. повторная попытка — этот статус устанавливается, когда вы нажимаете сообщение.
  2. удален — этот статус устанавливается, когда абонент отвечает 200.
  3. зарезервировано — этот статус устанавливается, когда абонент отвечает 202.
  4. ошибка — если Iron исчерпал количество повторных попыток и если он все еще не получил ответ 200, статус устанавливается на ошибку.

Примечание. Когда ваше приложение отвечает ошибками 4xx или 5xx (что обычно означает, что с сервером что-то пошло не так), Iron ожидает дольше указанного времени ожидания.

Вывод

Push-очереди — это не ракетостроение, когда вы смотрите на них шаг за шагом. Попробуйте сами и скажите нам, что вы думаете в комментариях ниже! Я искренне надеюсь, что это помогло вам понять эту часто пугающую тему. Я настоятельно рекомендую вам прочитать: http://dev.iron.io/mq/reference/push_queues/ . Обратите внимание, что вы можете найти исходный код этой статьи по адресу: https://github.com/rajivseelam/laravel-queues .

Спасибо за прочтение!