简体   繁体   中英

Polly with cancellation token is not working for synchronous thread

I'm new to Polly so there may be a completely different approach compared to the one I'm trying to do and that would be perfectly OK. My goals are this:

  1. I am using timeout strategy as: TimeoutStrategy.Optimistic
  2. I want to timeout the call for given clientTimeOut
  3. I am using cancellation token to timeout the thread

I am using cancellation token to timeout the call but somehow the below code is not working. I am not creating a new thread while adding a cancellation token but using the same thread to honoured the timeout. Does it always need to add the cancellation token in asynchronous call ie ExecuteAsync() or use another thread for it? Can someone help me with what is wrong with the below code and why timeout is not working?

Note: Using TimeoutStrategy.Pessimist will work for me but I can't use this due to some other usecase. I need to read the https headers from request context, and we will loose this information when using async call. Hence I need to use the sync call.

public TResult ExecuteWrapper<TResult>(Func<CancellationToken ,TResult> func)
{
    int attempts = 0;
    int retryCounter = 3;
    int waitTime = 1000;
    int clientTimeOut = 10000;
    var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(10000));
    var cancellationToken = cts.Token;

    RetryPolicy retryPolicy = Policy.Handle<Exception>().Retry(retryCounter);
    retryPolicy = Policy.Handle<Exception>().WaitAndRetry(retryCounter, sleepDurationProvider: attempt => TimeSpan.FromMilliseconds(this.waitTime), onRetry: (exception, timeSpan) =>
    {
          logRetryException(timeSpan, attempts++, exception);
    });
    
    PolicyWrap retrypolicywrap = retryPolicy.Wrap(Policy.Timeout(TimeSpan.FromMilliseconds(clientTimeOut), TimeoutStrategy.Optimistic));
    return retrypolicywrap.Execute(func, cancellationToken);
} 

public void BaseFunction(){
   var result = ExecuteWrapper(() => DummyFunctionToSleepTheThread())
}

public string DummyFunctionToSleepTheThread(){
   //Reading http header from the request context
   //which will lost if we use async call 
   //Hence we can't use Task.Delay(milliseconds) here.
    int milliseconds = 15000;
    System.Threading.Thread.Sleep(milliseconds);
    return "SUCCESS";
}

I tried adding the cancellation token but it did not honoured the timeout.

You can't use optimistic timeout strategy to cancel a Thread . This strategy uses the co-operative behaviour of the CancellationToken . Thread s do not natively support CancellationToken like Task s.

So, you have two options. Fall back to pessimistic timeout strategy or use Task instead of Thread .

As far as I can tell from the your code you haven't designed your solution to take advantage of Task s and async-await. So, try to use the pessimistic strategy.


UPDATE #1

Here is a simple app which demonstrates the difference

( Please note that bellow overload of Timeout requires seconds not milliseconds )

public static void Main()
{
    var optimisticTimeout = Policy.Timeout(1, TimeoutStrategy.Optimistic);
    optimisticTimeout.Execute(ToBeDecoratedMethod);
    var pessimisticTimeout = Policy.Timeout(1, TimeoutStrategy.Pessimistic);
    try
    {
        pessimisticTimeout.Execute(() => ToBeDecoratedMethod());
    }
    catch(TimeoutRejectedException)
    {
        Console.WriteLine("Timed out");
    }
}

public static void ToBeDecoratedMethod()
{
    Console.WriteLine("Before Sleep");
    Thread.Sleep(1_500);
    Console.WriteLine("After Sleep");
}

The output will be:

Before Sleep
After Sleep
Before Sleep
Timed out

The working code can be found on this do.net fiddle link .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM