GlobalModel.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System.Text.Json;
  2. using Microsoft.Extensions.Caching.Memory;
  3. namespace economy.Models.Price.Global
  4. {
  5. public class GlobalModel
  6. {
  7. private readonly Alpha_API _alphaAPI;
  8. private readonly IMemoryCache _cache;
  9. private readonly EconomyContext? _context;
  10. public GlobalModel(Alpha_API alphaAPI, IMemoryCache cache, EconomyContext? context = null)
  11. {
  12. _alphaAPI = alphaAPI;
  13. _cache = cache;
  14. _context = context;
  15. }
  16. // 천연가스 시세 조회
  17. public async Task<NaturalGas.Response> GetNaturalGasPriceInfo(NaturalGas.Request request)
  18. {
  19. string cacheKey = $"Alpha_NATURAL_GAS_{request.Interval}";
  20. // 캐시에 데이터가 존재하면 반환
  21. if (_cache.TryGetValue(cacheKey, out NaturalGas.Response cachedData))
  22. {
  23. return cachedData;
  24. }
  25. NaturalGas.Response parseData = new();
  26. try
  27. {
  28. var uriBuilder = new UriBuilder(_alphaAPI.APIUrl)
  29. {
  30. Path = "/query",
  31. Query = $"function=NATURAL_GAS&interval={request.Interval}&apikey={_alphaAPI.APIKey}"
  32. };
  33. var response = await _alphaAPI.httpClient.GetAsync(uriBuilder.Uri);
  34. if (response.IsSuccessStatusCode)
  35. {
  36. var jsonString = await response.Content.ReadAsStringAsync();
  37. parseData = JsonSerializer.Deserialize<NaturalGas.Response>(jsonString);
  38. if (parseData.Data is not null)
  39. {
  40. // 캐시에 저장 (메모리 1일 + DB에 마지막 성공 응답 영구 보관)
  41. _cache.Set(cacheKey, parseData, TimeSpan.FromDays(1));
  42. await SaveDbCacheAsync(cacheKey, jsonString);
  43. return parseData;
  44. }
  45. }
  46. response.EnsureSuccessStatusCode();
  47. }
  48. catch (HttpRequestException e)
  49. {
  50. Console.WriteLine($"Request error: {e.Message}");
  51. }
  52. // 호출 실패/한도 초과 시 DB에 보관된 마지막 성공 응답으로 대체
  53. var fallback = await LoadDbCacheAsync<NaturalGas.Response>(cacheKey);
  54. return fallback ?? new NaturalGas.Response();
  55. }
  56. // 국제 원자재 시세 조회 (구리, 알루미늄, 밀, 섬유(면화), 설탕, 커피, 원자재 종합지수)
  57. public async Task<Commodity.Response> GetCommodityPriceInfo(string function, string interval)
  58. {
  59. string cacheKey = $"Alpha_{function}_{interval}";
  60. // 캐시에 데이터가 존재하면 반환
  61. if (_cache.TryGetValue(cacheKey, out Commodity.Response cachedData))
  62. {
  63. return cachedData;
  64. }
  65. Commodity.Response parseData = new();
  66. try
  67. {
  68. var uriBuilder = new UriBuilder(_alphaAPI.APIUrl)
  69. {
  70. Path = "/query",
  71. Query = $"function={function}&interval={interval}&apikey={_alphaAPI.APIKey}"
  72. };
  73. var response = await _alphaAPI.httpClient.GetAsync(uriBuilder.Uri);
  74. if (response.IsSuccessStatusCode)
  75. {
  76. var jsonString = await response.Content.ReadAsStringAsync();
  77. parseData = JsonSerializer.Deserialize<Commodity.Response>(jsonString);
  78. if (parseData.Data is not null)
  79. {
  80. // 캐시에 저장 (메모리 1일 + DB에 마지막 성공 응답 영구 보관)
  81. _cache.Set(cacheKey, parseData, TimeSpan.FromDays(1));
  82. await SaveDbCacheAsync(cacheKey, jsonString);
  83. return parseData;
  84. }
  85. }
  86. response.EnsureSuccessStatusCode();
  87. }
  88. catch (HttpRequestException e)
  89. {
  90. Console.WriteLine($"Request error: {e.Message}");
  91. }
  92. // 호출 실패/한도 초과 시 DB에 보관된 마지막 성공 응답으로 대체
  93. var fallback = await LoadDbCacheAsync<Commodity.Response>(cacheKey);
  94. return fallback ?? new Commodity.Response();
  95. }
  96. // 성공 응답을 DB에 upsert (DB 장애 시에도 서비스에는 영향 없음)
  97. private async Task SaveDbCacheAsync(string cacheKey, string payload)
  98. {
  99. if (_context is null)
  100. {
  101. return;
  102. }
  103. try
  104. {
  105. var row = await _context.ApiCache.FindAsync(cacheKey);
  106. if (row is null)
  107. {
  108. _context.ApiCache.Add(new ApiCacheEntry { CacheKey = cacheKey, Payload = payload, UpdatedAt = DateTime.Now });
  109. }
  110. else
  111. {
  112. row.Payload = payload;
  113. row.UpdatedAt = DateTime.Now;
  114. }
  115. await _context.SaveChangesAsync();
  116. }
  117. catch (Exception e)
  118. {
  119. Console.WriteLine($"ApiCache save error: {e.Message}");
  120. }
  121. }
  122. // DB에 보관된 마지막 성공 응답 조회 (없거나 DB 장애면 null)
  123. private async Task<T?> LoadDbCacheAsync<T>(string cacheKey) where T : class
  124. {
  125. if (_context is null)
  126. {
  127. return null;
  128. }
  129. try
  130. {
  131. var row = await _context.ApiCache.FindAsync(cacheKey);
  132. return row is null ? null : JsonSerializer.Deserialize<T>(row.Payload);
  133. }
  134. catch (Exception e)
  135. {
  136. Console.WriteLine($"ApiCache load error: {e.Message}");
  137. return null;
  138. }
  139. }
  140. }
  141. }