Persistent-request библиотека для надежных запросов

от автора

Всем привет!

В этой статье расскажу, как решил написать библиотеку https://packagist.org/packages/xman12/persistent-request и что там внутри.

Как и любая библиотека, эта решает свои задачи, а именно гарантированное выполнение запроса и последующую обработку. Я находил, как минимум, одно решение, которое работает с подобной проблематикой — это https://temporal.io/, но система монструозная, а мне хотелось, чего-то более легкого и приземленного, поэтому я решил написать свое решение этой задачи.

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

  • работать с laravel (на этом фреймворке построен сайт, где нужно было решить задачу с обработкой запросов)

  • легкое и гибкое использование

  • минимум зависимостей

Вот что в итоге вышло по зависимостям:

— php >=7.4

— guzzlehttp/guzzle >=6.3

— laravel/framework >=5.4

— laravel/serializable-closure «1.*»

На схеме ниже показал, как работает библиотека:

Ну что ж, приступим к установке и разбору. 

Для начала библиотеку нужно подключить через composer:

composer require xman12/persistent-request

Затем подключаем провайдера в config/app.php

'providers' => [PersistentRequest\ServiceProvider::class]

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

php artisan queue:work

Разберем более подробно на примере.

Для начала инициализируем сервис:

$requestService = app(\PersistentRequest\Services\RequestServiceInterface::class);

Теперь нужно создать объект запроса: 

$requestGuzzle = new \GuzzleHttp\Psr7\Request('get', 'https://google.com');

После нужно подготовить объект RequestDTO, и происходит вся магия:

$requestDTO = new \PersistentRequest\DTO\RequestDTO(   $requestGuzzle,    \PersistentRequest\Events\SuccessEvent::class,    30,   5,   function (\GuzzleHttp\Psr7\Response $response) {         if (200 !== $response->getStatusCode()) {             throw new \Exception('error processed');         } }); 

Первым аргументом идет класс для запроса в guzzle.

Вторым идет \PersistentRequest\Events\SuccessEvent::class — это имя события, которое будет вызвано после успешного выполнения запроса, в него будет передан объект Psr\Http\Message\ResponseInterface, с которым можно работать в listener.

Третьим передается время в секундах, через которое библиотека повторит запрос, в случае неудачи.

Четвертым аргументом передается количество попыток после которого прекратятся запросы, тут нужно быть аккуратным если не передать тут значение то запрос будет выполняться бесконечно — пока не станет успешным. В случае если число попыток передается и по итогу времени количество отказов равняется лимиту, в таком случае очередь удаляется и отправляется событие DeleteRequestEvent, на него стоит подписаться если вы хотите отслеживать данное поведение.

Пятым аргументом передается анонимная функция, расширяющая работу с сервисом. Невалидные или валидные ответы обрабатываются, и, если нужно повторить запрос, то достаточно кинуть исключение. Так можно, не реализовывая listener, описать логику обработки ответа в анонимной функции.

Далее выполняется сам запрос:

$requestService->execute($requestDTO);

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

Соберем все в кучу:

$requestService = app(\PersistentRequest\Services\RequestServiceInterface::class); $requestGuzzle = new \GuzzleHttp\Psr7\Request('get', 'https://google.com'); $requestDTO = new \PersistentRequest\DTO\RequestDTO(   $requestGuzzle,    \PersistentRequest\Events\SuccessEvent::class,   30,   5,   function (\GuzzleHttp\Psr7\Response $response) {   if (200 !== $response->getStatusCode()) {       throw new \Exception('error processed');   } });  $requestService->execute($requestDTO);

Если запрос по какой-то причине «упал», то вызывается RetryRequestJob.php, который передается экземпляр RequestDTO с необходимыми параметрами.

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


ссылка на оригинал статьи https://habr.com/ru/articles/767112/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *