Bounded worker pool with Parallel.ForEachAsync

C#
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

static async Task<(int Ok, IReadOnlyCollection<Exception> Errors)> RunPoolAsync<T>(
    IEnumerable<T> items, Func<T, Task> work, int workers)
{
    int ok = 0;
    var errors = new ConcurrentBag<Exception>();
    await Parallel.ForEachAsync(items, new ParallelOptions { MaxDegreeOfParallelism = workers },
        async (item, _) =>
        {
            try { await work(item); Interlocked.Increment(ref ok); }
            catch (Exception ex) { errors.Add(ex); }
        });
    return (ok, errors);
}