@ayseeq

Реализовать асинхронный запрос к апи поставщика на yii2?

Была задача реализовать обновление данных товаров через апи поставщика, но у них ограничение на запрос на 50 позиций на 1 запрос и последовательными запросами отрабатывает более 3 часов т.к. нужно запросить данные около 200тысяч позиций

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

<?php

namespace tms\api;

use Yii;
use yii\base\Exception;
use yii\helpers\ArrayHelper;
use GuzzleHttp\Client;

class SimalandApi
{
    /**
     * @var string Базовый URL для запросов
     */
    public $baseUrl = 'url';

    /**
     * @var string Токен для авторизации в API.
     */
    private $token = 'token'; // Укажите ваш токен здесь

    /**
     * @var array Соответствие между ID поставщика и ID склада.
     */
    private $warehouseId = [
        8 => 2, // Sima-Land
        21 => 1, // Sima-Land M
    ];

    /**
     * @var int Ограничение количества товаров, получаемых за один запрос к API.
     */
    public const FETCH_ITEMS_LIMIT = 50;

    /**
     * Выполняет запрос к API для получения данных товаров по их SID.
     *
     * @param array $sids Массив идентификаторов SID товаров.
     * @return array Массив данных товаров.
     * @throws Exception Если произошла ошибка при запросе к API.
     */
    public function fetchProductsBySids(array $sids): array
    {
        $client = new Client();

        try {
            $response = $client->request('GET', $this->baseUrl, [
                'query' => [
                    'sid' => implode(',', $sids), // Преобразуем массив sids в строку для запроса
                    'expand' => 'stocks', // Получаем также информацию о запасах
                ],
                'headers' => [
                    'Authorization' => $this->token,
                    'Accept' => 'application/json',
                ],
            ]);

            if ($response->getStatusCode() === 200) {
                $body = $response->getBody();
                return json_decode($body, true);
            } else {
                Yii::error('Непредвиденный статус ответа ', $response->getStatusCode());
            }
        } catch (\Exception $e) {
            Yii::error('Ошибка запроса к API: ' . $e->getMessage());
            throw new Exception("Ошибка запроса к API: " . $e->getMessage());
        }

        return [];
    }

    /**
     * Подготавливает данные о товарах для обновления запасов.
     *
     * @param int $supplierId Идентификатор поставщика.
     * @param array $productItems Массив данных товаров.
     * @return array Массив подготовленных данных о товарах.
     */
    public function prepareProductDataForStock(int $supplierId, array $productItems): array
    {
        $result = [];
        $warehouseId = $this->warehouseId[$supplierId];

        foreach ($productItems as $productItem) {
            $stocks = ArrayHelper::index($productItem['stocks'], 'stock_id');

            $stock = 0;
            if ($stocks[$warehouseId]) {
                // Может отсутствовать balance. Вместо него приходит balance_text со значением "достаточно".
                // В таком случае устанавливается остаток 777
                $stock = isset($stocks[$warehouseId]['balance']) ? $stocks[$warehouseId]['balance'] : 777;
            }

            $result[$productItem['sid']] = [
                'price' => $productItem['price'],
                // 'min_quantity' => $productItem['min_qty'], // TODO Кажется, что min_quantity самое подходящее поле
                'stock' => $stock,
            ];
        }

        return $result;
    }
}
  • Вопрос задан
  • 138 просмотров
Пригласить эксперта
Ответы на вопрос 1
SilenceOfWinter
@SilenceOfWinter Куратор тега PHP
та еще зажигалка...
в guzzle есть асинхронные запросы
насчет времени выполнения - меняете значение в скрипте, если опция залочена, то как и говорилось через консольное приложение/очереди
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы