YahooFinanceHttp.cs 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. using Microsoft.Extensions.Logging;
  2. namespace Infrastructure.StockData;
  3. /// <summary>
  4. /// Yahoo Finance v8 chart 무인증 JSON 호출 공통 — User-Agent 헤더는 DI 에서 기본 부여(Yahoo 는 UA 없으면 거부).
  5. /// 간단 3회 재시도(2s/4s 백오프). 404(심볼 없음)는 재시도 없이 null 반환 → 호출측이 해당 심볼 skip.
  6. /// Stooq 봇차단(JS PoW) 도입으로 세계지수·종목 수집 소스를 Yahoo v8 로 전환(2026-07-09).
  7. /// </summary>
  8. internal static class YahooFinanceHttp
  9. {
  10. public const string ClientName = "YahooFinance";
  11. private const int MaxAttempts = 3;
  12. /// <summary>성공 시 응답 본문(JSON), 404 면 null. 그 외 실패는 재시도 후 예외.</summary>
  13. public static async Task<string?> GetStringWithRetryAsync(HttpClient client, string url, ILogger logger, CancellationToken ct)
  14. {
  15. for (var attempt = 1; ; attempt++)
  16. {
  17. try
  18. {
  19. using var response = await client.GetAsync(url, ct);
  20. if ((int)response.StatusCode == 404)
  21. {
  22. return null;
  23. }
  24. response.EnsureSuccessStatusCode();
  25. return await response.Content.ReadAsStringAsync(ct);
  26. }
  27. catch (Exception ex) when (ex is not OperationCanceledException && attempt < MaxAttempts)
  28. {
  29. logger.LogWarning(ex, "[Yahoo] HTTP 실패 — 재시도 {Attempt}/{Max}", attempt, MaxAttempts);
  30. await Task.Delay(TimeSpan.FromSeconds(2 * attempt), ct);
  31. }
  32. }
  33. }
  34. }