using MessageFlow; namespace MessageFlow.Samples; /// /// Shows how the cancellation token flows from /// down to every handler. /// public static class CancellationSample { /// /// Builds a chain whose handler observes the cancellation token before doing any work. /// /// The composed chain. public static IChain BuildChain() => Chain.Create() .Use(async (request, next, cancellationToken) => { cancellationToken.ThrowIfCancellationRequested(); return await next(request, cancellationToken).ConfigureAwait(false); }) .WithFallback(async (request, _) => { await Task.Yield(); return $"processed:{request}"; }) .Build(); /// /// Executes a request and turns cancellation into a readable description. /// /// The chain to execute. /// The request to send. /// A token used to cancel the operation. /// The response, or the name of the cancellation exception. public static async Task DescribeAsync( IChain chain, string request, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(chain); try { return await chain.ExecuteAsync(request, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { return nameof(OperationCanceledException); } } /// /// Runs the sample once with a live token and once with an already cancelled token. /// /// The writer receiving the sample output. /// A token used to cancel the operation. /// The successful response followed by the name of the cancellation exception. public static async Task> RunAsync( TextWriter output, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(output); var chain = BuildChain(); using var cancelled = new CancellationTokenSource(); await cancelled.CancelAsync().ConfigureAwait(false); var results = new List(); foreach (var token in new[] { cancellationToken, cancelled.Token }) { var description = await DescribeAsync(chain, "job", token).ConfigureAwait(false); results.Add(description); await output.WriteLineAsync($"job => {description}").ConfigureAwait(false); } return results; } }