2014-01-24 5 views
3

Mono.Mac (3.2.3)을 사용하여 서버와 통신하는 일부 REST 요청을 사용하고 있으며 재시도 메커니즘으로 HTTP 작업에 여러 번 시도하려고합니다. 그들이 실패하거나 시간이 초과되면.특정 오류가 발생하면 백그라운드에서 작업 다시 시작

다음과 같은 내용이 있습니다.

var tries = 0; 
while (tries <= ALLOWED_TRIES) 
{ 
    try 
    { 
     postTask.Start(); 
     tries++; 
     if (!postTask.Wait(Timeout)) 
     { 
      throw new TimeoutException("Operation timed out"); 
     } 
     break; 
    } catch (Exception e) { 
     if (tries > ALLOWED_TRIES) 
     { 
      throw new Exception("Failed to access Resource.", e); 
     } 
    } 
} 

여기서 태스크는 부모 메소드의 매개 변수를 사용합니다.

var postTask = new Task<HttpWebResponse>(() => {return someStuff(foo, bar);}, 
    Task.Factory.CancellationToken, 
    Task.Factory.CreationOptions); 

문제는 먼저 완료 (이후 실패)의 후 작업이 postTask.Start() 다시 실행하고 싶지 않은 것 같다. 이 작업을 수행하는 간단한 방법이 있습니까, 아니면 이런 식으로 작업을 잘못 사용합니까? 작업을 초기 상태로 재설정하는 메소드가 있습니까? 아니면 어떤 종류의 팩토리를 사용하는 것이 더 낫지는 않습니까?

답변

3

당신은 실제로 몇 가지 이유를 들어, 여기에 Task을 오용하고 있습니다 :

  • 당신은 두 번 이상 같은 작업을 실행할 수 없습니다. 완료되면 완료됩니다.

  • Task 개체를 수동으로 구성하는 것은 좋지 않으므로, Task.RunTask.Factory.Start이 있습니다.

  • IO 바인딩 작업을 수행하는 작업에 Task.Run/Task.Factory.Start을 사용하지 않아야합니다. 이들은 작업을 수행하기 위해 스레드를 ThreadPool에서 "빌려"CPU 작업에 사용됩니다. 대신 전용 비동기 Task 기반 API를 사용하십시오.이 전용 스레드는 전용 스레드가 필요하지 않습니다. 예를 들어

, 당신은 UI 스레드에서 GetResponseWithRetryAsync를 호출하고 아직 응답 UI를 유지할 수 아래 :

async Task<HttpWebResponse> GetResponseWithRetryAsync(string url, int retries) 
{ 
    if (retries < 0) 
     throw new ArgumentOutOfRangeException(); 

    var request = WebRequest.Create(url); 
    while (true) 
    { 
     try 
     { 
      var result = await request.GetResponseAsync(); 
      return (HttpWebResponse)result; 
     } 
     catch (Exception ex) 
     { 
      if (--retries == 0) 
       throw; // rethrow last error 
      // otherwise, log the error and retry 
      Debug.Print("Retrying after error: " + ex.Message); 
     } 
    } 
} 

더 읽기 :

"Task.Factory.StartNew" vs "new Task(...).Start"합니다.

Task.Run vs Task.Factory.StartNew.

+0

이것은 C# 5.0을 가정합니다. 그것은 그것이 옵션이라는 질문에서 나에게 명확하지 않습니다. – svick

+0

@svick 코드는 읽을 수있는 것은 아니지만 'ContinueWith' 콜백을 사용하여 동일한 작업을 수행 할 수 있습니다. – Noseratio

+1

@svick, 여기는 [.NET 4.0 버전] (http://stackoverflow.com/a/21346870/1768303)으로, 저를위한 학습 활동으로, 나는 'async/await'를 더 좋아한다는 것을 배웠습니다. – Noseratio

0

나는이 같은 일을 추천 할 것입니다 :

private int retryCount = 3; 
... 

public async Task OperationWithBasicRetryAsync() 
{ 
    int currentRetry = 0; 

    for (; ;) 
    { 
    try 
    { 
     // Calling external service. 
     await TransientOperationAsync(); 

     // Return or break. 
     break; 
    } 
    catch (Exception ex) 
    { 
     Trace.TraceError("Operation Exception"); 

     currentRetry++; 

     // Check if the exception thrown was a transient exception 
     // based on the logic in the error detection strategy. 
     // Determine whether to retry the operation, as well as how 
     // long to wait, based on the retry strategy. 
     if (currentRetry > this.retryCount || !IsTransient(ex)) 
     { 
     // If this is not a transient error 
     // or we should not retry re-throw the exception. 
     throw; 
     } 
    } 

    // Wait to retry the operation. 
    // Consider calculating an exponential delay here and 
    // using a strategy best suited for the operation and fault. 
    Await.Task.Delay(); 
    } 
} 

// Async method that wraps a call to a remote service (details not shown). 
private async Task TransientOperationAsync() 
{ 
    ... 
} 

이 코드는 Microsoft에서 재시도 패턴 디자인에서입니다. 당신은 그것을 여기에서 확인할 수 있습니다 : https://msdn.microsoft.com/en-us/library/dn589788.aspx

관련 문제