ARC-79Recommended
Start tasks only inside a scope that waits for them
Start concurrent tasks only inside a scope that waits for all of them before it returns. When one task fails, the scope cancels the others and passes the error up.
How to do it
A task started and forgotten keeps running after its request ends, holds connections, and loses its error. This is called structured concurrency. Use Python's asyncio.TaskGroup from Python 3.11, errgroup in Go, coroutineScope in Kotlin, or task groups in Swift. In JavaScript, Promise.all waits but does not cancel the others, so pass them one shared AbortSignal. Work that must outlive the request goes to a queue, as Move slow work out of the request says. This extends Await every async call.
Examples
Python example
async def load_dashboard(account_id: str) -> Dashboard:
async with asyncio.TaskGroup() as group:
invoices = group.create_task(fetch_invoices(account_id))
usage = group.create_task(fetch_usage(account_id))
alerts = group.create_task(fetch_alerts(account_id))
return Dashboard(invoices.result(), usage.result(), alerts.result())
Go example
func loadDashboard(ctx context.Context, accountID string) (Dashboard, error) {
group, ctx := errgroup.WithContext(ctx)
var d Dashboard
group.Go(func() (err error) { d.Invoices, err = fetchInvoices(ctx, accountID); return })
group.Go(func() (err error) { d.Usage, err = fetchUsage(ctx, accountID); return })
group.Go(func() (err error) { d.Alerts, err = fetchAlerts(ctx, accountID); return })
return d, group.Wait()
}
How to check
A lint or search rule finds no asyncio.create_task outside a task group and no bare go statement in request handlers. A test makes one of three tasks fail and asserts that the other two were cancelled.
Sources
Related rules
- SCL-16 Move slow work out of the request in Scaling
- ARC-33 Await every async call in Clean code and architecture
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/architecture/concurrency/structured-concurrency">Agent Wranglers clean code and architecture playbook</a>. In code you write, add a comment next to it with the same link.