| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- 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<NaturalGas.Response> 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<NaturalGas.Response>(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<NaturalGas.Response>(cacheKey);
- return fallback ?? new NaturalGas.Response();
- }
- // 국제 원자재 시세 조회 (구리, 알루미늄, 밀, 섬유(면화), 설탕, 커피, 원자재 종합지수)
- public async Task<Commodity.Response> 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<Commodity.Response>(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<Commodity.Response>(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<T?> LoadDbCacheAsync<T>(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<T>(row.Payload);
- }
- catch (Exception e)
- {
- Console.WriteLine($"ApiCache load error: {e.Message}");
- return null;
- }
- }
- }
- }
|