Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 16.06.2018 18:57:59

Помещение запроса в очередь и отправка ответа из очереди

Здравствуйте, дорогие ларавельчане!
Дошло дело в проекте до использования механизма очередей. И, в принципе, там всё понятно, кроме одного момента.
Имеется API на который шлёт запросы сторонний сервис и получает в ответ JSON. На данный момент, без очередей, всё работает как надо, без сюрпризов. Но, поступила задача "пропускать" эти запросы через очередь, чтобы предотвратить лежачее положение сервера в особо "жаркие" моменты. К сожалению, решения данной задачи пока найти не удалось.
Была попытка передачи инстанса Illuminate\Http\Request в воркер, но фреймворк ругается но невозможность сериализации замыкания.

Route::get('getjson', function (\Illuminate\Http\Request $request){
    $job = (new GetJSONJob($request))->onConnection('redis');
    dispatch($job);
});

Воркер

class GetJSONJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $request;

    /**
     * Create a new job instance.
     *
     * @param \Illuminate\Http\Request $request
     * @return void
     */
    public function __construct(\Illuminate\Http\Request $request)
    {
        $this->request = $request;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        return redirect()->action('CommonAPIController@getJSON', $this->request);
    }
}

Надеюсь, что вы мне поможете. Заранее благодарю!

Не в сети

#2 25.06.2018 22:45:28

Re: Помещение запроса в очередь и отправка ответа из очереди

У вас в корне подход к решению задачи не верен, очередь может помочь если приложению не важен ответ отработки задачи в очереди, например: отправка письма; определение гео координат сторонним сервисом.
В вашем случае идёт запрос и ждёт ответ, зависимый от данных в запросе - очередь не поможет.
В handle() не может быть данных для возврата return redirect()->...

Надеюсь я правильно понял то, что вы хотели создать.

Не в сети

#3 29.06.2018 20:41:27

Re: Помещение запроса в очередь и отправка ответа из очереди

Жаль, что так.
У меня была мысль, что получится передать объект запроса в воркер, а из воркера в контроллер. Что-то на подобии как происходит в Middleware. Там ведь тоже объект запроса из Middleware передаётся в контроллер или callback.
Есть уверенность, что как-то разработчики такую задачу решают, но вот как...?

Не в сети

#4 30.06.2018 03:29:04

Re: Помещение запроса в очередь и отправка ответа из очереди

У вас неправильное понимание, что такое очереди задач вообще. Они не предназначены для того

чтобы предотвратить лежачее положение сервера в особо "жаркие" моменты

А они служат лишь для того, чтобы ускорить время отклика для запроса, вынося какие-то действия в отдельный процесс.

Рассмотрим простой пример:

Route::get('/job', function () {
  // текущее время
  $start = date('h:i:s');

  // ожидание в течениe 10 секунд
  sleep(10);

  // время на момент завершения ожидания
  $end = date('h:i:s');

  return $start . ' - ' . $end;
});

При переходе на /job выведет что-то типа: "04:40:21- 04:40:31". Как видим, десять секунд на выполнение.


Теперь, если мы вынесем sleep(10) в задачу (я не буду приводить код самой задачи, там в handle просто вызывается sleep(10))

Route::get('/job', function () {
  // текущее время
  $start = date('h:i:s');

  // ожидание в течениe 10 секунд поставится как задача в очередь
  dispatch(new App\Jobs\SleepTask);

  // время на момент завершения работы этого кода
  $end = date('h:i:s');

  return $start . ' - ' . $end;
});

Теперь при переходе на /job будет выведено что-то типа: "04:50:12- 04:50:12". Как видим, меньше секунды на выполнение. Хотя sleep(10) будет выполнен, просто это будет сделано на фоне, вы этого не увидите.

Надеюсь понятно описал.


Возвращаясь к тому, что же делать для того

чтобы предотвратить лежачее положение сервера в особо "жаркие" моменты

1) Я бы изучил ваш метод getJSON. Оптимизировал бы код, использовал "жадную" загрузку там, где это необходимо. Банально добавил бы пагинацию. Пусть клиент учитывает это (хотя задумываться об этом надо было раньше, ладно если у вас 1 клиент... А если 100? 10000?).
2) Ограничил бы количество запросов одним в несколько секунд/минуту (throttle) для этого маршрута.
3) Проверил бы индексы в БД.
4) Проверил бы настройки MySQL.
5) Да кучу всего еще можно придумать. Вплоть до репликации бд и работы в методе getJSON с отдельной базой на отдельном сервере...

Изменено FrDR (30.06.2018 03:30:39)

Не в сети

#5 30.06.2018 09:47:36

Re: Помещение запроса в очередь и отправка ответа из очереди

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

Не в сети

Подвал раздела