Я извлекаю данные из API через программу на C #, но производительность программы меня не убеждает - PullRequest
0 голосов
/ 11 апреля 2019

Как гласит заголовок: я извлекаю данные из API через программу C # (в данном случае API Shopify).Прежде всего, API Shopify получил следующее ограничение: он использует алгоритм leaky bucket для обработки входящих запросов, где его размер корзины равен 40 запросам , а скорость утечка 2 запроса в секунду .Таким образом, если корзина заполнена и новый запрос попадает в API, сам API ответит сообщением об ошибке HTTP 429 (слишком много запросов) . Вы можете проверить больше об этом в документации Shopify: https://help.shopify.com/en/api/getting-started/api-call-limit.

Я извлекаю некоторые данные из Shopify, нажимая на их API, и на самом деле объем данных немного (например, 80-90k)транзакций заказа), но из-за ограничений API довольно сложно достичь этого за минимально возможное время.Таким образом, в основном то, что делает моя программа, - это 40 вызовов API-интерфейса Shopify, я жду их, затем засыпаю программу на пару секунд (10 секунд) и выполняю следующие 40 вызовов.Из-за того, что я нажимаю следующий пакет, не дожидаясь соответствующего времени, чтобы избежать ответов HTTP 429, я реализовал шаблон повторных попыток для повторных HTTP-вызовов, которые не выполняются из-за некоторой временной ошибки (например, HTTP 429, 503 и т. Д.), Поэтому я 'я стараюсь изо всех сил стараться не получать частичные результаты.

Так вот, что делает моя программа; Я вытащил 85 000 транзакций за 11 часов (что, по-моему, довольно плохо), но я пытаюсь выяснить, где еще можно улучшить, чтобы сократить время обработки.Я знаю, что в API Shopify есть узкое место, но это не входит в мои задачи ... Как вы думаете, ребята, есть какой-то метод / подход для улучшения извлечения данных из API?Я хотел бы услышать ваши мнения / мысли по этому поводу.Я полностью открыт для любых предложений!Кроме того, я был бы очень благодарен.

Проверьте фрагмент кода ниже, чтобы увидеть одну из функций моей программы, которая показывает логику, объясненную выше.Я также хотел бы поблагодарить любой обзор кода;Например, достаточно ли производительности, предлагаемой методом AsParallel из класса ParallelEnumerable, для ситуации, с которой я работаю?

public void BulkInsertOrdersEvents(List<long> orders, IPersistence persistence)
{
    if (orders != null && orders.Any())
    {
        return;
    }

    short ordersPerBurst = 40;
    int totalOrders = orders.Count;
    int ordersProcessed = 0;

    while (true)
    {
        if (ordersProcessed >= totalOrders)
        {
            break;
        }

        var ordersForProcess = orders.Skip(ordersProcessed).Take(ordersPerBurst);
        var orderEventsBag = new ConcurrentBag<string>();

        ordersForProcess.AsParallel().ForAll((orderId) =>
        {
            var httpCallParameters = new Dictionary<string, object>();
            httpCallParameters.Add("orderId", orderId);

            Console.WriteLine("Started processing the order {0}", orderId);

            int pages = CalculatePages(ShopifyEntity.OrderEvent, httpCallParameters);

            if (pages == 0)
            {
                return;
            }

            string getOrderEventsEndpoint = string.Format(ShopifyApiEndpoints.GET_ORDER_EVENTS_BY_ORDER_ID, orderId) + $"?limit=250"; ;

            Parallel.For(1, pages + 1, (index) =>
            {
                //Create HTTP client for call Shopify API
                var httpClient = GetHttpClient();
                var httpHeaders = GetHttpHeaders();

                //Call Shopify API for return order transactions
                string orderEvents = httpClient.Get(getOrderEventsEndpoint + "&page=" + index, httpHeaders);

                Console.WriteLine("Obtained page {0} of Events from Order {1}", index, orderId);

                //Put the order's events for current page into concurrent bag
                orderEventsBag.Add(orderEvents);
            });


            Console.WriteLine("Finished processing the order {0}", orderId);
        });

        Dictionary<string, object> saveParameters = null;

        if (persistence.GetType().Name.Equals(typeof(BlobPersistence).Name))
        {
            string fileName = string.Format(ShopifyApiConstants.ORDER_EVENTS_FILE_NAME_TEMPLATE, DateTime.UtcNow.ToString("yyyyMMddHHmmss"));
            saveParameters = new Dictionary<string, object>()
                {
                    {"fileName", fileName}
                };
        }

        //Merge all events pages into a single JSON and store it.
        var orderEventsJson = JsonHelper.MergeJsons(orderEventsBag.ToArray());
        persistence.Save(orderEventsJson, saveParameters);

        Thread.Sleep(TimeSpan.FromSeconds(5));

        ordersProcessed += ordersPerBurst;
    }

}

Я упустил упомянуть, что я также сохраняю эти результаты наХранилище BLOB-объектов Azure;но это совсем не проблема!Там, где моя программа отнимает так много времени, это получение данных из Shopify.

Большое спасибо, ребята!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...