async Task <TResult> IConveyor <TData, TResult> .ProcessDataAsync(TData data, CancellationToken cancellation, int attemptsCount) => await _third.ProcessDataAsync(await _second.ProcessDataAsync(await _first .ProcessDataAsync(data, cancellation, Math.Min(_first.MaxAttempts, attemptsCount)) .ConfigureAwait(false), cancellation, Math.Min(_second.MaxAttempts, attemptsCount)) .ConfigureAwait(false), cancellation, Math.Min(_third.MaxAttempts, attemptsCount)) .ConfigureAwait(false);
/// <inheritdoc cref="ProcessDataAsync{TData,TResult}(IPriorityConveyor{TData,TResult},IEnumerable{TData},int,CancellationToken,int,bool)" /> public static async IAsyncEnumerable <TResult> ProcessDataAsync <TData, TResult>(this IPriorityConveyor <TData, TResult> conveyor, IAsyncEnumerable <TData> data, int priority = 0, [EnumeratorCancellation] CancellationToken cancellation = default, int attemptsCount = 1) where TData : notnull { _ = conveyor ?? throw new ArgumentNullException(nameof(conveyor)); var channel = Channel.CreateUnbounded <Task <TResult> >(new UnboundedChannelOptions { SingleReader = true, SingleWriter = true }); var reader = channel.Reader; var writer = channel.Writer; _ = Task.Run(async() => { try { await foreach (var item in data.WithCancellation(cancellation).ConfigureAwait(false)) { await writer.WriteAsync(conveyor.ProcessDataAsync(item, priority, cancellation, attemptsCount), cancellation) .ConfigureAwait(false); } } catch (OperationCanceledException ex) { await writer.WriteAsync(Task.FromCanceled <TResult>(ex.CancellationToken), CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { await writer.WriteAsync(Task.FromException <TResult>(ex), cancellation).ConfigureAwait(false); } finally { writer.Complete(); } }, cancellation); while (await reader.WaitToReadAsync(cancellation).ConfigureAwait(false)) { yield return(await(await reader.ReadAsync(cancellation).ConfigureAwait(false)).ConfigureAwait(false)); } }
/// <summary> Batch process data with giver <paramref name="priority" /> </summary> /// <param name="conveyor"> Conveyor instance </param> /// <param name="data"> Data to process </param> /// <param name="cancellation"> Processing cancellation token </param> /// <param name="attemptsCount"> Retry on fail attempts count </param> /// <param name="priority"> Operation priority </param> /// <param name="enqueueAll"> Option to enqueue all data first </param> /// <typeparam name="TData"> Input data type </typeparam> /// <typeparam name="TResult"> Processing result type </typeparam> /// <returns> Processing result task enumeration </returns> /// <exception cref="ArgumentNullException"> Thrown if <paramref name="conveyor" /> or <paramref name="data" /> is NULL </exception> public static async IAsyncEnumerable <TResult> ProcessDataAsync <TData, TResult>(this IPriorityConveyor <TData, TResult> conveyor, IEnumerable <TData> data, int priority = 0, [EnumeratorCancellation] CancellationToken cancellation = default, int attemptsCount = 1, bool enqueueAll = false) where TData : notnull { _ = conveyor ?? throw new ArgumentNullException(nameof(conveyor)); var results = (data ?? throw new ArgumentNullException(nameof(data))).Select(item => conveyor.ProcessDataAsync(item, priority, cancellation, attemptsCount)); if (enqueueAll) { results = results.ToList(); } foreach (var result in results) { yield return(await result.ConfigureAwait(false)); } }