/// <inheritdoc cref="AccessAsync{TResource,TResult}(IAccessQueue{TResource},IEnumerable{IAsyncAccess{TResource,TResult}},CancellationToken,int,bool)" /> public static async IAsyncEnumerable <TResult> AccessAsync <TResource, TResult>(this IAccessQueue <TResource> accessQueue, IAsyncEnumerable <IAsyncAccess <TResource, TResult> > accesses, [EnumeratorCancellation] CancellationToken cancellation = default, int attemptsCount = 1) where TResource : notnull { _ = accessQueue ?? throw new ArgumentNullException(nameof(accessQueue)); 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 access in accesses.WithCancellation(cancellation).ConfigureAwait(false)) { await writer.WriteAsync(accessQueue.EnqueueAsyncAccess(access, 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 asynchronous access actions </summary> /// <param name="accessQueue"> Access Queue instance </param> /// <param name="accesses"> Access actions to process </param> /// <param name="cancellation"> Processing cancellation token </param> /// <param name="attemptsCount"> Retry on fail attempts count </param> /// <param name="enqueueAll"> Option to enqueue all data first </param> /// <typeparam name="TResource"> Shared resource type </typeparam> /// <typeparam name="TResult"> Processing result type </typeparam> /// <returns> Processing result task enumeration </returns> /// <exception cref="ArgumentNullException"> Thrown if <paramref name="accessQueue" /> or <paramref name="accesses" /> is NULL </exception> public static async IAsyncEnumerable <TResult> AccessAsync <TResource, TResult>(this IAccessQueue <TResource> accessQueue, IEnumerable <IAsyncAccess <TResource, TResult> > accesses, [EnumeratorCancellation] CancellationToken cancellation = default, int attemptsCount = 1, bool enqueueAll = false) where TResource : notnull { _ = accessQueue ?? throw new ArgumentNullException(nameof(accessQueue)); var results = (accesses ?? throw new ArgumentNullException(nameof(accesses))).Select(access => accessQueue.EnqueueAsyncAccess(access, cancellation, attemptsCount)); if (enqueueAll) { results = results.ToList(); } foreach (var result in results) { yield return(await result.ConfigureAwait(false)); } }