using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class KiwoomApiManager
{
private static KiwoomApiManager _instance;
private static readonly object _lock = new object();
// 요청에 대한 응답을 기다리는 TaskCompletionSource들을 저장할 사전
private readonly Dictionary<string, TaskCompletionSource<string>> _responseTasks = new Dictionary<string, TaskCompletionSource<string>>();
private const int TimeoutMilliseconds = 6000; // 타임아웃 6초
private const int MaxRetries = 5; // 최대 재시도 횟수
private KiwoomApiManager()
{
// 키움 OpenAPI 초기화 및 이벤트 핸들러 설정
// _api.OnReceiveTrData += OnReceiveTrData;
}
public static KiwoomApiManager Instance
{
get
{
lock (_lock)
{
if (_instance == null)
_instance = new KiwoomApiManager();
return _instance;
}
}
}
public async Task<string> SendRequestWithRetryAsync(string requestId, string trCode, params object[] parameters)
{
for (int attempt = 1; attempt <= MaxRetries; attempt++)
{
try
{
// 요청을 보내고 응답을 기다림
var response = await SendRequestAsync(requestId, trCode, parameters);
return response; // 응답이 성공적으로 도착하면 반환
}
catch (TimeoutException)
{
if (attempt == MaxRetries)
{
throw new TimeoutException("응답이 여러 번 누락되었습니다. 최대 재시도 횟수를 초과했습니다.");
}
else
{
Console.WriteLine($"재시도 중... ({attempt}/{MaxRetries})");
}
}
}
throw new Exception("예상치 못한 오류가 발생했습니다."); // 논리적으로 도달하지 않지만 안전을 위해 추가
}
private async Task<string> SendRequestAsync(string requestId, string trCode, params object[] parameters)
{
var tcs = new TaskCompletionSource<string>();
var cts = new CancellationTokenSource(TimeoutMilliseconds); // 타임아웃 설정
// 타임아웃이 발생하면 Task를 취소
using (cts.Token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: false))
{
lock (_responseTasks)
{
_responseTasks[requestId] = tcs;
}
// 요청 보내기
// _api.CommRqData(requestId, trCode, parameters);
try
{
// 응답 대기
return await tcs.Task;
}
catch (TaskCanceledException)
{
throw new TimeoutException("응답이 설정된 시간 안에 도착하지 않았습니다.");
}
finally
{
// 요청 완료 후 정리
lock (_responseTasks)
{
_responseTasks.Remove(requestId);
}
}
}
}
private void OnReceiveTrData(object sender, AxKHOpenAPILib._DKHOpenAPIEvents_OnReceiveTrDataEvent e)
{
string requestId = e.sScrNo;
TaskCompletionSource<string> tcs;
lock (_responseTasks)
{
if (_responseTasks.TryGetValue(requestId, out tcs))
{
_responseTasks.Remove(requestId);
}
}
if (tcs != null)
{
tcs.SetResult("응답 데이터"); // 실제 응답 데이터로 교체
}
}
}
728x90
댓글