using Bitget_Server.Application.Options; using Bitget_Server.Application.State; using Bitget_Server.Domain.Enums; using Bitget_Server.Infrastructure.Bitget; using Microsoft.Extensions.Options; namespace Bitget_Server.Application.BackgroundServices; /// /// 기존 MainForm.DataCalculateThread (1000ms loop) 이식. /// BitgetWebSocketClient 가 수집한 메시지를 주기적으로 꺼내어 candleDataLists 로 병합한다. /// public class WebSocketCalcBackgroundService : BackgroundService { private readonly BitgetWebSocketClient _ws; private readonly MarketState _state; private readonly BitgetOptions _options; private readonly ILogger _logger; public WebSocketCalcBackgroundService( BitgetWebSocketClient ws, MarketState state, IOptions options, ILogger logger) { _ws = ws; _state = state; _options = options.Value; _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("WebSocketCalcBackgroundService 시작 (Interval={Ms}ms)", _options.WebSocketCalcIntervalMs); var delay = TimeSpan.FromMilliseconds(Math.Max(200, _options.WebSocketCalcIntervalMs)); while (!stoppingToken.IsCancellationRequested) { try { await Task.Delay(delay, stoppingToken).ConfigureAwait(false); // WebSocket 이 꺼져 있으면 처리할 데이터도 없으므로 skip if (!_ws.IsConnected) continue; List intervalsSnapshot; lock (_state.SyncRoot) intervalsSnapshot = _state.IntervalList.ToList(); _ws.CalculateDataList(BitgetWebSocketType.캔들정보, intervalsSnapshot); } catch (OperationCanceledException) { /* shutdown */ } catch (Exception ex) { _logger.LogWarning(ex, "WebSocket 집계 루프 오류"); } } _logger.LogInformation("WebSocketCalcBackgroundService 종료"); } }