Worker Pool
How the scheduler dispatches jobs to your task functions across threads and async runtimes.
How the scheduler dispatches jobs to your task functions across threads and async runtimes.
The worker pool dispatches jobs from the scheduler to PythonNode.jsJava task functions.
async defasynchandler functions to the async runtime.std::thread. The GIL is acquired per task via Python::with_gil() — independent across workers.Sync handlers run on an OS-thread pool owned by the Rust core — independent across workers, with no event loop to block.Handlers run on a JVM ExecutorService — a cached pool by default, fixed with concurrency(n) — fed by the JNI dispatch bridge.async def tasks are dispatched to an AsyncTaskExecutor on a Python daemon thread; PyResultSender bridges results back.async handlers run on a native async pool — no thread per job; each runs on your Node event loop and its promise is awaited back into the core.Every job is an executor task; the handler's return value (or exception) is bridged back into the Rust scheduler as the job outcome.workers × 2
to provide backpressure.std::thread threads.
The GIL is only acquired when calling Python task code.Python::with_gil(). The scheduler and result handler release the GIL via
py.allow_threads().async def tasks bypass the thread pool entirely.
A NativeAsyncPool sends them to a dedicated AsyncTaskExecutor running on a
Python daemon thread. PyResultSender (a #[pyclass]) bridges results back
into the Rust scheduler.threading.local for current_job;
async tasks use contextvars.ContextVar, which is properly scoped across
await boundaries and isolated between concurrent coroutines.std::thread
pool owned by the core, independent across workers — there's no global lock to
coordinate.async handlers bypass the thread pool. They run
on your Node event loop as independent async invocations; each returned promise
is awaited and its result bridged back into the Rust scheduler.currentJob()) is carried
with AsyncLocalStorage, so it stays correct across await boundaries and
between concurrently dispatched jobs.java.util.concurrent
ExecutorService owned by the worker — a cached pool by default, a fixed pool
with concurrency(n), or a resizable pool under autoscale(...).TaskScope for resource
resolution, entered and exited around the handler on its executor thread —
thread-confined, so concurrent jobs never share per-task state.