Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Async, Concurrency, and Backpressure

Apalis uses async for waiting on brokers and handlers, concurrency for multiple in-flight jobs, and an executor only when the application explicitly supplies one.

Ordinary async functions are already the right shape

An async function is a value implementing FnMut(Args...) -> Future. TaskFn supplies Tower’s poll_ready and call, the generated implementations extract up to sixteen typed arguments, and IntoResponse normalizes the output. No handler macro or runtime-owned callback interface is required.

There are two separate concurrency mechanisms

CallAllUnordered can retain many service futures in a FuturesUnordered. Actual admission is controlled by readiness. .concurrency(n) adds Tower’s ConcurrencyLimitLayer; when all permits are held, poll_ready becomes Pending, and the worker stops polling the backend for another task.

.parallelize(tokio::spawn) solves a different problem. Its generic executor turns a handler future into an independently scheduled future. Apalis accepts a function with the necessary input/output shape rather than naming Tokio in its core types.

backend ready? ─┐
service ready? ─┴─ yes → poll one job → push future ─┐
                                                     ├→ FuturesUnordered
shutdown? ───────── yes → stop admission → drain ───┘

Concurrency is not parallelism

Many network-bound jobs can make progress on one executor thread. They become parallel only if the executor runs them simultaneously on multiple threads. CPU-bound or blocking work still needs an appropriate blocking pool; merely making its function async does not make it cooperative.

Cancellation is resource accounting

WorkerContext::track wraps important futures. Its pinned drop logic decrements the task count even when a future is cancelled or dropped. Shutdown therefore tracks ownership, not just successful return paths.

Shutdown is a change in admission policy

Shutdown is a cloneable future backed by shared atomic state and a waker. Once signalled, readiness refuses new work. CallAllUnordered drains existing futures, then calls Backend::poll_close so buffered acknowledgements or broker resources can flush. Monitor coordinates several workers and may impose a final deadline.