본문 바로가기
카테고리 없음

task 샘플

by Knowledge Store In Hyunsoft 2024. 11. 6.
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

댓글