using System.Text.Json; using Microsoft.Extensions.Caching.Memory; namespace economy.Models.Price.Global { public class GlobalModel { private readonly Alpha_API _alphaAPI; private readonly IMemoryCache _cache; private readonly EconomyContext? _context; public GlobalModel(Alpha_API alphaAPI, IMemoryCache cache, EconomyContext? context = null) { _alphaAPI = alphaAPI; _cache = cache; _context = context; } // 천연가스 시세 조회 public async Task GetNaturalGasPriceInfo(NaturalGas.Request request) { string cacheKey = $"Alpha_NATURAL_GAS_{request.Interval}"; // 캐시에 데이터가 존재하면 반환 if (_cache.TryGetValue(cacheKey, out NaturalGas.Response cachedData)) { return cachedData; } NaturalGas.Response parseData = new(); try { var uriBuilder = new UriBuilder(_alphaAPI.APIUrl) { Path = "/query", Query = $"function=NATURAL_GAS&interval={request.Interval}&apikey={_alphaAPI.APIKey}" }; var response = await _alphaAPI.httpClient.GetAsync(uriBuilder.Uri); if (response.IsSuccessStatusCode) { var jsonString = await response.Content.ReadAsStringAsync(); parseData = JsonSerializer.Deserialize(jsonString); if (parseData.Data is not null) { // 캐시에 저장 (메모리 1일 + DB에 마지막 성공 응답 영구 보관) _cache.Set(cacheKey, parseData, TimeSpan.FromDays(1)); await SaveDbCacheAsync(cacheKey, jsonString); return parseData; } } response.EnsureSuccessStatusCode(); } catch (HttpRequestException e) { Console.WriteLine($"Request error: {e.Message}"); } // 호출 실패/한도 초과 시 DB에 보관된 마지막 성공 응답으로 대체 var fallback = await LoadDbCacheAsync(cacheKey); return fallback ?? new NaturalGas.Response(); } // 국제 원자재 시세 조회 (구리, 알루미늄, 밀, 섬유(면화), 설탕, 커피, 원자재 종합지수) public async Task GetCommodityPriceInfo(string function, string interval) { string cacheKey = $"Alpha_{function}_{interval}"; // 캐시에 데이터가 존재하면 반환 if (_cache.TryGetValue(cacheKey, out Commodity.Response cachedData)) { return cachedData; } Commodity.Response parseData = new(); try { var uriBuilder = new UriBuilder(_alphaAPI.APIUrl) { Path = "/query", Query = $"function={function}&interval={interval}&apikey={_alphaAPI.APIKey}" }; var response = await _alphaAPI.httpClient.GetAsync(uriBuilder.Uri); if (response.IsSuccessStatusCode) { var jsonString = await response.Content.ReadAsStringAsync(); parseData = JsonSerializer.Deserialize(jsonString); if (parseData.Data is not null) { // 캐시에 저장 (메모리 1일 + DB에 마지막 성공 응답 영구 보관) _cache.Set(cacheKey, parseData, TimeSpan.FromDays(1)); await SaveDbCacheAsync(cacheKey, jsonString); return parseData; } } response.EnsureSuccessStatusCode(); } catch (HttpRequestException e) { Console.WriteLine($"Request error: {e.Message}"); } // 호출 실패/한도 초과 시 DB에 보관된 마지막 성공 응답으로 대체 var fallback = await LoadDbCacheAsync(cacheKey); return fallback ?? new Commodity.Response(); } // 성공 응답을 DB에 upsert (DB 장애 시에도 서비스에는 영향 없음) private async Task SaveDbCacheAsync(string cacheKey, string payload) { if (_context is null) { return; } try { var row = await _context.ApiCache.FindAsync(cacheKey); if (row is null) { _context.ApiCache.Add(new ApiCacheEntry { CacheKey = cacheKey, Payload = payload, UpdatedAt = DateTime.Now }); } else { row.Payload = payload; row.UpdatedAt = DateTime.Now; } await _context.SaveChangesAsync(); } catch (Exception e) { Console.WriteLine($"ApiCache save error: {e.Message}"); } } // DB에 보관된 마지막 성공 응답 조회 (없거나 DB 장애면 null) private async Task LoadDbCacheAsync(string cacheKey) where T : class { if (_context is null) { return null; } try { var row = await _context.ApiCache.FindAsync(cacheKey); return row is null ? null : JsonSerializer.Deserialize(row.Payload); } catch (Exception e) { Console.WriteLine($"ApiCache load error: {e.Message}"); return null; } } } }