У меня есть класс декоратора, который добавляет возможность ограничивать число запросов http для обращения к API:
public class RateLimitedHttpClient : IHttpClient
{
public RateLimitedHttpClient(System.Net.Http.HttpClient client)
{
_client = client;
_client.Timeout = TimeSpan.FromMinutes(30);
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
}
public async Task<string> ReadAsync(string url)
{
if (!_sw.IsRunning)
_sw.Start();
await Delay();
using var response = await _client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
private async Task Delay()
{
var totalElapsed = GetTimeElapsedSinceLastRequest();
while (totalElapsed < MinTimeBetweenRequests)
{
await Task.Delay(MinTimeBetweenRequests - totalElapsed);
totalElapsed = GetTimeElapsedSinceLastRequest();
};
_timeElapsedOfLastHttpRequest = (int)_sw.Elapsed.TotalMilliseconds;
}
private int GetTimeElapsedSinceLastRequest()
{
return (int)_sw.Elapsed.TotalMilliseconds - _timeElapsedOfLastHttpRequest;
}
private readonly System.Net.Http.HttpClient _client;
private readonly Stopwatch _sw = new Stopwatch();
private int _timeElapsedOfLastHttpRequest;
private const int MinTimeBetweenRequests = 100;
}
Однако я замечаю, что в строке, указанной ниже, я получаю сообщение в отладчикеэто говорит о том, что the next statement will execute when the current thread returns
.
var epsDataPoints = await _downloader.GetEPSData(cik);
foreach (var eps in epsDataPoints)
{
// getting VS2019 debugger message here!
// assuming that the line above is deadlocking....
Console.WriteLine($"{cik} :: {eps.DateInterval} :: {eps.EPS}");
}
Когда я открываю диспетчер задач, пропускная способность сети становится равной 0, и все останавливается с приложением, отличным от Console.WriteLine
выше.
Класс EPSDownloader, использующий IHttpClient, приведен ниже:
public class EPSDownloader
{
public EPSDownloader(IHttpClient client)
{
_client = client;
}
public async Task<IEnumerable<EPSDataPoint>> GetEPSData(int cik)
{
var epsDataPoints = new Dictionary<LocalDate, EPSDataPoint>();
var reportLinks = await GetReportLinks(cik);
foreach (var reportLink in reportLinks)
{
var xbrlLink = await GetXBRLLink(reportLink);
var epsData = await GetEPSData(xbrlLink);
foreach (var eps in epsData)
{
if (!epsDataPoints.ContainsKey(eps.DateInterval.End))
epsDataPoints.Add(eps.DateInterval.End, eps);
}
}
var list = epsDataPoints.OrderBy(d => d.Key).Select(e => e.Value).ToList();
return list;
}
private async Task<IList<string>> GetReportLinks(int cik)
{
// move this url elsewhere
var url = "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=" + cik +
"&type=10&dateb=&owner=include&count=100";
var srBody = await _client.ReadAsync(url); // consider moving this to srPage
var srPage = new SearchResultsPage(srBody);
return srPage.GetAllReportLinks();
}
private async Task<string> GetXBRLLink(string link)
{
var url = SEC_HOSTNAME + link;
var fdBody = await _client.ReadAsync(url);
var fdPage = new FilingDetailsPage(fdBody);
return fdPage.GetInstanceDocumentLink();
}
private async Task<IList<EPSDataPoint>> GetEPSData(string xbrlLink)
{
var xbrlBody = await _client.ReadAsync(SEC_HOSTNAME + xbrlLink);
var xbrlDoc = new XBRLDocument(xbrlBody);
return xbrlDoc.GetAllQuarterlyEPSData();
}
private readonly IHttpClient _client;
private const string SEC_HOSTNAME = "https://www.sec.gov";
}
Кажется, что есть проблема с HttpClient, но я не знаю почему.Не выдается никаких исключений, но я иногда вижу, что потоки закрылись с кодом 0.
Обновление: я фактически перезапустил свой компьютер во время работы приложения, и он снова начал нормально работать в течение примерно 20 минут, прежде чем задачаДиспетчер показал 0 для скорости сети и приложение просто сидело там.