@@ -96,49 +96,62 @@ public async ValueTask<T> ExecuteAsync<T>(Func<CancellationToken, ValueTask<T>>
9696 var startTime = _timeProvider . GetUtcNow ( ) ;
9797 var linkedCancellationToken = cancellationToken ;
9898 var timeoutToken = CancellationToken . None ;
99+ CancellationTokenSource timeoutCts = null ;
100+ CancellationTokenSource linkedCts = null ;
101+
99102 if ( Timeout > TimeSpan . Zero )
100103 {
101- timeoutToken = new CancellationTokenSource ( Timeout ) . Token ;
102- linkedCancellationToken = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken , timeoutToken ) . Token ;
104+ timeoutCts = new CancellationTokenSource ( Timeout ) ;
105+ timeoutToken = timeoutCts . Token ;
106+ linkedCts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken , timeoutToken ) ;
107+ linkedCancellationToken = linkedCts . Token ;
103108 }
104109
105- do
110+ try
106111 {
107- try
108- {
109- if ( attempts > 1 )
110- _logger ? . LogInformation ( "Retrying {Attempts} attempt after {Duration:g}..." , attempts . ToOrdinal ( ) , _timeProvider . GetUtcNow ( ) . Subtract ( startTime ) ) ;
111-
112- CircuitBreaker ? . BeforeCall ( ) ;
113- var result = await action ( linkedCancellationToken ) . AnyContext ( ) ;
114- CircuitBreaker ? . RecordCallSuccess ( ) ;
115- return result ;
116- }
117- catch ( BrokenCircuitException )
112+ do
118113 {
119- throw ;
120- }
121- catch ( Exception ex )
122- {
123- if ( ex is TaskCanceledException && timeoutToken . IsCancellationRequested )
124- throw new TimeoutException ( $ "Operation timed out after { Timeout : g} .") ;
114+ try
115+ {
116+ if ( attempts > 1 )
117+ _logger ? . LogInformation ( "Retrying {Attempts} attempt after {Duration:g}..." , attempts . ToOrdinal ( ) , _timeProvider . GetUtcNow ( ) . Subtract ( startTime ) ) ;
118+
119+ CircuitBreaker ? . BeforeCall ( ) ;
120+ var result = await action ( linkedCancellationToken ) . AnyContext ( ) ;
121+ CircuitBreaker ? . RecordCallSuccess ( ) ;
122+ return result ;
123+ }
124+ catch ( BrokenCircuitException )
125+ {
126+ throw ;
127+ }
128+ catch ( Exception ex )
129+ {
130+ if ( ex is TaskCanceledException && timeoutToken . IsCancellationRequested )
131+ throw new TimeoutException ( $ "Operation timed out after { Timeout : g} .") ;
125132
126- CircuitBreaker ? . RecordCallFailure ( ex ) ;
133+ CircuitBreaker ? . RecordCallFailure ( ex ) ;
127134
128- if ( attempts >= MaxAttempts || ( ShouldRetry != null && ! ShouldRetry ( attempts , ex ) ) || UnhandledExceptions . Contains ( ex . GetType ( ) ) )
129- throw ;
135+ if ( attempts >= MaxAttempts || ( ShouldRetry != null && ! ShouldRetry ( attempts , ex ) ) || UnhandledExceptions . Contains ( ex . GetType ( ) ) )
136+ throw ;
130137
131- _logger ? . LogError ( ex , "Retry error: {Message}" , ex . Message ) ;
138+ _logger ? . LogError ( ex , "Retry error: {Message}" , ex . Message ) ;
132139
133- await _timeProvider . SafeDelay ( GetAttemptDelay ( attempts ) , linkedCancellationToken ) . AnyContext ( ) ;
140+ await _timeProvider . SafeDelay ( GetAttemptDelay ( attempts ) , linkedCancellationToken ) . AnyContext ( ) ;
134141
135- ThrowIfTimedOut ( startTime ) ;
136- }
142+ ThrowIfTimedOut ( startTime ) ;
143+ }
137144
138- attempts ++ ;
139- } while ( attempts <= MaxAttempts && ! linkedCancellationToken . IsCancellationRequested ) ;
145+ attempts ++ ;
146+ } while ( attempts <= MaxAttempts && ! linkedCancellationToken . IsCancellationRequested ) ;
140147
141- throw new OperationCanceledException ( "Operation was canceled" , linkedCancellationToken ) ;
148+ throw new OperationCanceledException ( "Operation was canceled" , linkedCancellationToken ) ;
149+ }
150+ finally
151+ {
152+ linkedCts ? . Dispose ( ) ;
153+ timeoutCts ? . Dispose ( ) ;
154+ }
142155 }
143156
144157 public ResiliencePolicy Clone ( int ? maxAttempts = null , TimeSpan ? timeout = null , TimeSpan ? delay = null , Func < int , TimeSpan > getDelay = null )
0 commit comments