ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C# 비동기의 복병, TaskCanceledException 완벽 대처법 (타임아웃 해결)
    개발/C# 2026. 1. 26. 16:56
    반응형

    안녕하세요! 요즘 C# 개발의 대세는 역시 비동기(async/await)죠. 특히 네트워크로 데이터를 주고받거나 대용량 파일을 읽을 때 필수입니다. 그런데 코드를 잘 짜놓고 돌리다 보면 갑자기 이런 메시지를 마주할 때가 있습니다.

     

    에러 메시지: System.Threading.Tasks.TaskCanceledException: A task was canceled.

     

    "내가 취소한 적도 없는데 왜 취소됐다는 거야?"라며 당황하신 적 있으시죠? 오늘은 이 에러가 왜 발생하는지, 그리고 어떻게 하면 우아하게 '예외 처리'를 할 수 있는지 알려드릴게요.

     

     

    1. 원인은 보통 '타임아웃(Timeout)'입니다

    이 에러는 보통 **HttpClient**를 쓰거나 **CancellationToken**을 사용할 때 발생합니다.

    • 상황: 데이터를 요청했는데 서버가 너무 느려요.
    • 결과: "10초만 기다리기로 했는데 소식이 없네? 에잇, 취소!" 하고 프로그램이 스스로 작업을 중단해 버리는 겁니다.

    이건 에러라기보다 프로그램이 무한정 대기 상태(Freezing)에 빠지는 걸 막아주는 아주 기특한 보호 본능인 셈이죠.

     

    2. 실전 코드: "기다리다 지쳐 취소될 때"

    가장 흔한 HttpClient 예시를 볼까요?

    public async Task DownloadDataAsync()
    {
        using var client = new HttpClient();
        
        // 5초만 기다리겠다고 설정
        client.Timeout = TimeSpan.FromSeconds(5);
    
        try
        {
            // 5초 안에 응답이 안 오면 여기서 TaskCanceledException 발생!
            var result = await client.GetStringAsync("https://slow-api-server.com");
            Console.WriteLine(result);
        }
        catch (TaskCanceledException ex)
        {
            // "에러다!"가 아니라 "서버가 너무 느려서 일단 끊었어"라고 이해해야 합니다.
            Console.WriteLine("서버 응답이 너무 늦어 연결을 취소했습니다.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"기타 에러: {ex.Message}");
        }
    }

     

     

    3. 고수들은 'CancellationToken'을 씁니다

    실무에서는 사용자가 직접 "취소" 버튼을 누르거나, 프로그램이 종료될 때 진행 중인 작업을 멈추기 위해 **CancellationTokenSource**를 명시적으로 사용합니다.

    CancellationTokenSource cts = new CancellationTokenSource();
    
    // 3초 뒤에 무조건 취소하도록 예약
    cts.CancelAfter(3000);
    
    try
    {
        await LongRunningJobAsync(cts.Token);
    }
    catch (OperationCanceledException) // TaskCanceledException의 부모 격입니다.
    {
        Console.WriteLine("사용자 혹은 시스템에 의해 작업이 중단되었습니다.");
    }

     

     

     

    4. (꿀팁) 에러인지 취소인지 구분하는 법

    TaskCanceledException이 터졌을 때, 이게 시간이 다 돼서(Timeout) 그런 건지, 아니면 **코드에서 취소(Cancel)**를 시킨 건지 헷갈릴 때가 있죠?

    • ex.CancellationToken.IsCancellationRequested 가 false라면? -> 십중팔구 타임아웃 때문입니다.
    • **true**라면? -> 누군가(혹은 시스템이) 명시적으로 취소 버튼을 누른 겁니다.

     

     

    마무리하며

    **TaskCanceledException**을 만났을 때 당황하지 마세요. 이건 여러분의 프로그램이 '먹통'이 되지 않도록 AI(아니, 닷넷 런타임 ㅎㅎ)가 열일하고 있다는 증거니까요. 이제 try-catch로 이 녀석을 잘 달래주기만 하면 됩니다!

    오늘 여러분의 비동기 코드는 안녕하신가요? 혹시 타임아웃 때문에 고생 중이라면 지금 바로 Timeout 설정을 체크해 보세요!

    반응형
Designed by Tistory.