Why Task.WhenAll can crash services when processing 10,000 items concurrently:
Task.WhenAll spawns all 10,000 tasks immediately, overwhelming downstream databases and triggering HTTP 429 rate limits.
Controlled Concurrency with Parallel.ForEachAsync:
await Parallel.ForEachAsync(itemUrls, new ParallelOptions
{
MaxDegreeOfParallelism = 8, // Run at most 8 tasks concurrently
CancellationToken = cancellationToken
}, async (url, ct) =>
{
await DownloadAndProcessAsync(url, ct);
});Maintains a steady pool of active workers with built-in cancellation and error aggregation!