StructuredConcurrency 0.9.0

dotnet add package StructuredConcurrency --version 0.9.0
                    
NuGet\Install-Package StructuredConcurrency -Version 0.9.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="StructuredConcurrency" Version="0.9.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="StructuredConcurrency" Version="0.9.0" />
                    
Directory.Packages.props
<PackageReference Include="StructuredConcurrency" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add StructuredConcurrency --version 0.9.0
                    
#r "nuget: StructuredConcurrency, 0.9.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package StructuredConcurrency@0.9.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=StructuredConcurrency&version=0.9.0
                    
Install as a Cake Addin
#tool nuget:?package=StructuredConcurrency&version=0.9.0
                    
Install as a Cake Tool

StructuredConcurrency

Structured concurrency for C# and .NET. Run tasks in parallel inside a TaskGroup. The first failure cancels the other tasks, no task keeps running after the group returns, and you get the real error back instead of a TaskCanceledException.

dotnet add package StructuredConcurrency

Promise.all, Promise.any and Promise.allSettled in C#

using StructuredConcurrency;

// Promise.all: all results; the first failure cancels the rest
var (user, orders) = await TaskGroup.AllAsync(
    ct => GetUserAsync(id, ct),
    ct => GetOrdersAsync(id, ct));

// Promise.any: the first success; the others are cancelled
string data = await TaskGroup.AnyAsync(mirrors, (mirror, ct) => mirror.DownloadAsync(path, ct));

// Promise.allSettled: every outcome
TaskOutcome<Receipt>[] results = await TaskGroup.AllSettledAsync(orders, (order, ct) => ChargeAsync(order, ct));

Why not Task.WhenAll?

Three parallel calls; one fails after 300 ms, the others take 1.5 s and 2 s:

Approach Caller gets the error at Error the caller sees Work left running
Task.WhenAll 2,012 ms OrderService is down None, but 1.7 s of wasted calls
await one by one 301 ms OrderService is down 2 calls nobody waits for
Hand-written CancellationTokenSource 310 ms A task was canceled. None
TaskGroup 320 ms OrderService is down None

Task.WhenAny has the opposite problem: it returns the first task to complete, even if it failed, and leaves the rest running.

TaskGroup

await TaskGroup.RunAsync(async group =>
{
    foreach (var url in urls)
    {
        group.Run(ct => DownloadAsync(url, ct));
    }
}, new TaskGroupOptions { MaxConcurrency = 8 }, cancellationToken);
// Every download has finished here, or the first failure was thrown after the rest were cancelled.

Timeouts that cancel the work

task.WaitAsync(timeout) stops waiting, but the task keeps running. WithTimeoutAsync cancels it and returns once it has stopped, like Kotlin's withTimeout:

User user = await TaskGroup.WithTimeoutAsync(TimeSpan.FromSeconds(2), ct => LoadUserAsync(id, ct), cancellationToken);

Also included

  • Hedged requests: TaskGroup.HedgeAsync starts a second attempt when the first is slow
  • Supervisors: Supervisor.RunAsync restarts failing work with backoff, like Erlang/OTP
  • Rate limiting: TaskGroupOptions.RateLimiter with System.Threading.RateLimiting
  • Bounded parallel streams: SelectConcurrentAsync over collections and IAsyncEnumerable, and ChunkAsync
  • Go's singleflight (SingleFlight<TKey, TValue>) and per-key ordering (KeyedSequencer<TKey>)
  • Go's select for System.Threading.Channels, plus merge and broadcast
  • OpenTelemetry tracing and metrics
  • StructuredBackgroundService in the StructuredConcurrency.Hosting package: a BackgroundService that shuts down cleanly
  • Analyzers with code fixes that catch ignored cancellation tokens, work that escapes its group, and Task.WhenAll calls that don't cancel the rest on failure

Targets .NET 8 and later; trimming and NativeAOT compatible.

Full documentation, FAQ and benchmarks: github.com/gokhanertogan/StructuredConcurrency

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on StructuredConcurrency:

Package Downloads
StructuredConcurrency.Hosting

A BackgroundService whose work runs in a StructuredConcurrency TaskGroup: on shutdown every child task is cancelled and awaited, and a failing child stops the service with its real exception instead of leaving work running in the background, or restarts the service's work as a RestartPolicy allows.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.0 47 10/30/2026
0.8.0 109 10/23/2026
0.7.0 114 10/22/2026
0.6.0 104 10/22/2026
0.5.0 97 10/22/2026
0.4.0 91 10/22/2026
0.3.0 93 10/22/2026
0.2.1 78 10/22/2026
0.2.0 83 10/22/2026
0.1.0 84 10/21/2026