Class Awaiter
Provides a set of static methods for awaiting asynchronous operations.
public static class Awaiter
- Inheritance
-
Awaiter
Examples
The following example retries an asynchronous operation until it succeeds or the retry window closes. The delegate returns UnsuccessfulValue twice before returning SuccessfulValue, and the configured cancellation token is observed between attempts.
using System;
using System.Threading;
using System.Threading.Tasks;
using Cuemon.Threading;
namespace Cuemon.Threading;
public class AwaiterExample
{
public async Task DemonstrateAsync()
{
var attempt = 0;
var cancellationSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var result = await Awaiter.RunUntilSuccessfulOrTimeoutAsync(async () =>
{
attempt++;
if (attempt < 3)
{
await Task.Delay(50);
return new UnsuccessfulValue();
}
return new SuccessfulValue();
}, options =>
{
options.Timeout = TimeSpan.FromSeconds(5);
options.Delay = TimeSpan.FromMilliseconds(100);
options.CancellationToken = cancellationSource.Token;
});
Console.WriteLine($"Succeeded after {attempt} attempts: {result.Succeeded}");
}
}
Methods
RunUntilSuccessfulOrTimeoutAsync(Func<Task<ConditionalValue>>, Action<AsyncRunOptions>)
Repeatedly invokes the specified asynchronous method until it succeeds, cancellation is requested, the configured attempt limit is reached, or the configured Timeout retry window closes.
public static Task<ConditionalValue> RunUntilSuccessfulOrTimeoutAsync(Func<Task<ConditionalValue>> method, Action<AsyncRunOptions> setup = null)
Parameters
methodFunc<Task<ConditionalValue>>The asynchronous function delegate to execute, returning a ConditionalValue indicating success or failure.
setupAction<AsyncRunOptions>The AsyncRunOptions which may be configured.
Returns
- Task<ConditionalValue>
A task that represents the asynchronous operation. The task result contains the successful ConditionalValue returned by
method, or an unsuccessful value that aggregates caught exceptions when the retry policy completes without success.
Remarks
The retry window begins immediately before the initial invocation. The initial invocation always occurs, even when Timeout is Zero. No new invocation begins after the timeout deadline or once MaximumAttempts is reached. After an unsuccessful attempt or a caught exception, the next delay is capped to the smaller of Delay and the remaining timeout window. When the configured delay exceeds the remaining timeout window, the operation waits out the remainder of the window and completes without starting another invocation. Positive fractional-millisecond retry delays are rounded up to the next whole millisecond when the delay is scheduled. When Delay is Zero, MaximumAttempts must be configured with a positive value.
Cancellation is resolved from CancellationToken immediately before each attempt and immediately before each retry delay.
Because this overload does not pass a CancellationToken into method, timeout and cancellation cannot terminate work that is already executing inside the delegate; they only prevent additional retries or delays once the current invocation completes.
A completed invocation returning null is treated as a programming error and causes an InvalidOperationException without retrying.
Potential exceptions thrown by method are caught and collected. If the operation does not succeed before the retry policy completes, UnsuccessfulValue will be conditionally initialized as follows:
1: No caught exceptions; initialized with the default constructor.
2: One caught exception; initialized with the caught exception.
3: Two or more caught exceptions; initialized with an AggregateException containing the caught exceptions in encounter order.
Timeout does not abort an invocation already in progress. The current invocation is allowed to complete, and a successful result is returned even when it arrives after the timeout deadline. If an in-flight invocation completes unsuccessfully or throws after the deadline, the retry policy ends without another delay or attempt.
Exceptions
- ArgumentNullException
methodcannot be null.- ArgumentException
The configured AsyncRunOptions are not in a valid state.
- InvalidOperationException
methodcompleted successfully but returned a null ConditionalValue.- OperationCanceledException
Cancellation was requested before an attempt began, while a retry delay was pending, or
methodthrew an OperationCanceledException.