Пакетный запрос производит System.IO.IOException: слишком много открытых файлов - PullRequest
0 голосов
/ 13 июня 2019

У нас есть приложение API с использованием dotnet core 2.2, развернутое на сервере Ubuntu с использованием nginx, которое выполняет пакетный запрос к стороннему API. Мы не уверены, что на самом деле происходит за запросом, но наш пользовательский регистратор указывает исключение, которое происходит внутри пакетного модуля, который использует hangfire.

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

Код

FetchPrices

        try
        {
            var tasks = new List<Task<Price>>
            {
                //BTC
                Task.Run(async () => { return await GetPrice(CurrencyType.USD, CryptoCurrencyType.BTC); }),
                Task.Run(async () => { return await GetPrice(CurrencyType.EUR, CryptoCurrencyType.BTC); }),
                Task.Run(async () => { return await GetPrice(CurrencyType.JPY, CryptoCurrencyType.BTC); }),
                Task.Run(async () => { return await GetPrice(CurrencyType.CNY, CryptoCurrencyType.BTC); }),

                //ETH
                Task.Run(async () => { return await GetPrice(CurrencyType.USD, CryptoCurrencyType.ETH); }),
                Task.Run(async () => { return await GetPrice(CurrencyType.EUR, CryptoCurrencyType.ETH); }),
                Task.Run(async () => { return await GetPrice(CurrencyType.JPY, CryptoCurrencyType.ETH); }),
                Task.Run(async () => { return await GetPrice(CurrencyType.CNY, CryptoCurrencyType.ETH); }),
            };

            var results = await Task.WhenAll(tasks);
            using (var transaction = _priceRepository.BeginTransaction())
            {
                   Saving to DB
            }
        }
        catch (Exception e)
        {
             //The exception from GetPrice will be logged here
            _logger.WriteLogs(_appSettings.AssetRootPath, _appSettings.LogFilePrefix, "Batch", "AggregateExchange", null, e.Message, e.StackTrace, null);
        }

Функция GetPrice

        var tasks = new List<Task<PriceDetails>>();
        var ticker = new Ticker();
        var currencyStr = Enum.GetName(typeof(CurrencyType), type);

        var btcStr = Enum.GetName(typeof(CryptoCurrencyType), CryptoCurrencyType.BTC);
        var ethStr = Enum.GetName(typeof(CryptoCurrencyType), CryptoCurrencyType.ETH);

        var currency = c_type == CryptoCurrencyType.BTC ? $"{btcStr}-{currencyStr}" : c_type == CryptoCurrencyType.ETH ? $"{ethStr}-{currencyStr}" : $"{bceStr}-{currencyStr}";

        tasks.Add(Task.Run(async () => { return await GetPriceDetails(currency, PriceType.Spot); }));

        if (c_type != CryptoCurrencyType.BCE)
        {
            tasks.Add(Task.Run(async () => { return await GetPriceDetails(currency, PriceType.Sell); }));
            tasks.Add(Task.Run(async () => { return await GetPriceDetails(currency, PriceType.Buy); }));
        }


        var results = await Task.WhenAll(tasks); //An error occurs here

Функция GetPriceDetails

        var JsonObj = string.Empty;
        var partialUrl = string.Empty;

        if (type == PriceType.Buy)
        {
            partialUrl = string.Format(_appSettings.BuyPriceApi, currency);
        }
        else if (type == PriceType.Sell)
        {
            partialUrl = string.Format(_appSettings.SellPriceApi, currency);
        }
        else
        {
            partialUrl = string.Format(_appSettings.SpotPriceApi, currency);
        }

        JsonObj = await _apiRequest.SendCoinbaseRequest(
               HttpMethod.Get,
               _appSettings.CoinbaseRoot,
               partialUrl,
               _appSettings.ApiKey,
               _appSettings.ApiSecret
               );

        var res = JsonConvert.DeserializeObject<PriceReceiver>(JsonObj);
        return res.Data;

Есть ли какие-либо входные данные для любой возможности, которую нам нужно изучить, которая может сделать наш сервер тайм-аут?

То, что мы делаем, это перестраиваем и переиздаем API снова, но это повторяется. Мы подумали, что строка исключения throw в методе catch функции - это та, которая вызывает аварийное завершение API, но все равно происходит сбой даже после его удаления.

Это фактическое исключение.

System.IO.IOException
Too many open files

System.IO.IOException: Too many open files
   at Infrastructure.Base.ErrorLogger.WriteLogs(String rootPath, String filePrefix, String controller, String action, String request, String exceptionType, String logErrorMessage, String jwtToken) in /home/exchange/exchange-api/staging/bigcatman-api/BOE.Core/Infrastructure/Base/ErrorLogger.cs:line 48
   at Service.Batch.Implementation.AggregateExchange.FetchPrices() in /home/exchange/exchange-api/staging/bigcatman-api/BOE.Core/Service/Batch/Implementation/AggregateExchange.cs:line 179
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
...