/// <param name="first"> First conveyor </param> /// <param name="second"> Second conveyor </param> /// <exception cref="ArgumentNullException"> Thrown if <paramref name="first" /> or <paramref name="second" /> is NULL </exception> public PriorityConveyorChain(IPriorityConveyor <TData, TIntermediate> first, IConveyor <TIntermediate, TResult> second) { _first = first ?? throw new ArgumentNullException(nameof(first)); _second = new PriorityConveyorEmulator <TIntermediate, TResult>(second); _maxPriority = Math.Max(_first.MaxPriority, _second.MaxPriority); _maxAttempts = Math.Max(_first.MaxAttempts, _second.MaxAttempts); }
/// <param name="first"> First conveyor </param> /// <param name="second"> Second conveyor </param> /// <param name="third"> Third conveyor </param> /// <exception cref="ArgumentNullException"> Thrown if <paramref name="first" />, <paramref name="second" /> or <paramref name="third" /> is NULL </exception> public PriorityConveyorChain(IConveyor <TData, TFirstIntermediate> first, IConveyor <TFirstIntermediate, TSecondIntermediate> second, IPriorityConveyor <TSecondIntermediate, TResult> third) { _first = new PriorityConveyorEmulator <TData, TFirstIntermediate>(first); _second = new PriorityConveyorEmulator <TFirstIntermediate, TSecondIntermediate>(second); _third = third ?? throw new ArgumentNullException(nameof(third)); _maxAttempts = Math.Max(_first.MaxAttempts, Math.Max(_second.MaxAttempts, _third.MaxAttempts)); _maxPriority = Math.Max(_first.MaxPriority, Math.Max(_second.MaxPriority, _third.MaxPriority)); }
/// <inheritdoc cref="ProcessDataAsync{TData,TResult}(IPriorityConveyor{TData,TResult},IEnumerable{TData},int,CancellationToken,int,bool)" /> public static IAsyncEnumerable <TResult> ProcessDataAsync <TData, TResult>(this IEnumerable <TData> data, IPriorityConveyor <TData, TResult> conveyor, int priority = 0, CancellationToken cancellation = default, int attemptsCount = 1, bool enqueueAll = false) where TData : notnull => (conveyor ?? throw new ArgumentNullException(nameof(conveyor))).ProcessDataAsync(data, priority, cancellation, attemptsCount, enqueueAll);
/// <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)); } }
/// <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)); } }