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

Rust API

The complete API documentation is on docs.rs. This page maps the crates and their main types, so you know where to look.

Cratedocs.rsUse it for
cronoqdocs.rs/cronoqEmbedding the scheduler in a tokio application. Start here.
cronoq-coredocs.rs/cronoq-coreThe sans-IO engine: custom drivers, simulations, deterministic tests.
cronoq-store-postgresdocs.rs/cronoq-store-postgresDurable state and leader election for Scheduler<Bytes, Bytes>.
cronoq-store-sqlitedocs.rs/cronoq-store-sqliteThe same, in a local SQLite file.
cronoq-protodocs.rs/cronoq-protoGenerated gRPC clients and servers (cronoq_proto::v1), PROTOCOL_VERSION.
cronoq-serverdocs.rs/cronoq-serverThe server binary, and worker::run_worker for Rust workers.

MSRV: Rust 1.94 (edition 2024) for every crate.

cronoq

Building a scheduler

Scheduler::builder() returns a Builder<P, O> (P = payload type, O = output type).

Builder methodDefaultDescription
pool(Pool)–Add a pool (at least one; the first is the default pool).
resource(ResourceConfig)–Add a shared semaphore or token bucket.
priority(PriorityConfig)built-inClass scores and aging.
urgency(UrgencyConfig)built-inDeadline urgency curve.
store(impl Store) / store_arc(Arc<dyn Store>)MemoryStorePersistence backend.
emit_transitions(bool)falseBroadcast every transition on events(), not only terminal ones.
queue_capacity(n)8192Capacity of the submission channel.
events_capacity(n)4096Broadcast buffer of events(); slow subscribers lose the oldest events.
max_store_outage(Duration)5 minHow long a store may report StoreError::Unavailable before the scheduler stops.
drop_grace(Duration)5 sGrace for running attempts when every handle is dropped without shutdown.
output_cache(n)1024Recent results kept for handles attached after a task finished: outputs, and the messages of tasks that did not succeed (0 disables).
configure(FnOnce(&mut CoreConfig))–Engine-wide settings: bounds, retention, metrics window, seed.
build().await–Start on the current tokio runtime (waits for leadership with a persistent store).
build_blocking()–Start a BlockingScheduler on its own runtime thread.

Pool<P, O>:

MethodDescription
Pool::new(name)Autoscaled pool (1 to 10 workers by default).
Pool::fixed(name, n)Fixed size, no autoscaling.
workers(min, initial, max)min is the lower bound on the autoscaler's desired capacity; initial is the capacity at start (at most max, and not raised to min); max is the upper bound.
executor(impl Executor), executor_arc(..), executor_fn(async fn)How attempts run.
scaler(impl Scaler), scaler_arc(..)Capacity backend (default SlotScaler: in-process slots).
autoscale(AutoscaleConfig), no_autoscale()Autoscaling policy.
configure(FnOnce(&mut PoolConfig))Every other pool setting (bounds, overflow, retry, lease TTL, max hold, tenant fairness, ...).

Scheduler<P, O>

A cheap-to-clone handle. Every method is async and returns Result<_, Error>, except events(), pools() and clock(), which are synchronous and return their value directly, and stopped(), which is async and returns ().

MethodReturnsDescription
submit(task)TaskHandle<O>Submit and get an awaitable handle. Waits for queue space with the Wait overflow policy.
enqueue(task)SubmittedSubmit without a handle (cheaper; id, duplicate).
enqueue_many(tasks)Vec<Result<Submitted, Error>>Independent submissions in one round trip.
submit_batch(tasks)Vec<TaskHandle<O>>Atomic batch; tasks may depend on each other by key.
handle(target)Option<TaskHandle<O>>Attach to an existing task by id or key.
cancel(target)boolfalse if the task already finished.
status(target)Option<TaskStatus>None for unknown tasks.
list_tasks(pools, statuses, after, limit)Vec<TaskSummary>Live tasks in id order, filtered by pool (any if empty) and status (any if empty), with ids above after. Finished tasks are listed by a durable store (StoreQueries::list_finished).
list_recurring()Vec<RecurringInfo>Recurring schedules with their next occurrence and latest task.
snapshot()SnapshotMetrics and quality signals.
set_capacity(pool, n)()Report capacity for pools with an ExternalScaler.
set_group_capacity(pool, labels, n)()Report the slots of the pool's workers with exactly labels (Worker labels).
add_recurring(Recurring) / remove_recurring(name)() / boolCron schedules.
events()broadcast::Receiver<StatusEvent>Status events.
pools(), clock()&[Arc<str>], &ClockPool names; the engine clock.
stopped()()Resolves when the scheduler stops for any reason.
shutdown(grace)()Stop admitting, let running attempts finish for grace, then stop.

With a persistent store, submit, enqueue, submit_batch, cancel, add_recurring and remove_recurring return only after the change is durable.

TaskHandle<O> is a Future<Output = Result<Arc<O>, TaskFailure>> with id(), is_duplicate() and cancel().

Tasks and schedules

Task<P>: Task::new(payload) (or from_arc), then priority, pool, kind, key, deadline_in / deadline_at, start_in / start_at, start_tolerance, on_miss, duration_hint, timeout, retry, no_retry, after(target), dep(Dep), resource(name, units), tag(key, value), label(name, value) (a required worker label), tenant(name) (fair sharing). Builder order does not matter. Strings must not contain NUL characters.

Recurring<P>: Recurring::new(name, cron, template), then tz, overlap(OverlapPolicy) (Skip, Allow, Queue, QueueOnSuccess), tolerance, on_miss. The template's deadline_in applies per occurrence and its key is a prefix (<key>@<start>); it may not set an absolute deadline, a fixed start or dependencies.

Executors

TypeDescription
Executor<P, O>Trait: execute(ctx, Arc<P>) -> BoxFuture<Result<O, TaskError>>, optional abort(lease).
FnExecutorWraps an async fn(TaskContext, Arc<P>); what Pool::executor_fn uses.
TaskContextid, lease, attempt, pool, kind, key, tags, deadline, timeout, group (labels of the worker group the attempt was assigned to); is_cancelled(), cancelled().await, cancellation_token(), heartbeat(), tag(key), traceparent(); TaskContext::for_test(id) for unit tests.
TaskErrorRetryable { message, retry_after }, Permanent { message }, Cancelled; constructors retryable, retry_after, permanent, from_err.

A panicking executor fails its attempt permanently (panic: ...); the scheduler and other attempts keep running.

Errors

TypeVariants
ErrorSubmit(SubmitError), Shutdown, Config(String), Store(StoreError), Internal(String).
TaskFailureEnded { status, message }, OutputUnavailable { id }, Shutdown; status().
StoreErrorFenced, Unavailable(String), Other(String); is_transient().
ScaleErrorExternal, Other(String).

See Errors and status codes.

Capacity and persistence

TypeDescription
ScalerTrait: turn a desired capacity into workers.
SlotScalerDefault: capacity is a number of in-process concurrent attempts.
ExternalScalerCapacity is managed elsewhere and reported with set_capacity.
Store<P, O>Trait: persists (default true; false means the engine produces no mutations), acquire_leadership, release_leadership, commit, recover, load_output.
MemoryStoreNo persistence (default).
TimeBaseWall-clock anchor of engine time; the runtime always uses Unix-epoch time (unix_nanos_at_zero = 0).

Blocking facade

BlockingScheduler<P, O> (from Builder::build_blocking) has the same operations without async: submit, enqueue, enqueue_many, submit_batch, task_handle, cancel, status, snapshot, set_capacity, add_recurring, remove_recurring, events, scheduler, shutdown(grace). BlockingHandle<O> has id(), cancel(), wait() and wait_timeout(d).

Re-exports and features

Engine types are re-exported from cronoq-core: AutoscaleConfig, Bounds, Dep, EdgeCond, MissPolicy, OverflowPolicy, OverlapPolicy, PoolConfig, PoolSnapshot, Priority, PriorityConfig, ResourceConfig, ResourceKind, RetryPolicy, Snapshot, StatusEvent, SubmitError, Submitted, TaskId, TaskRef, TaskStatus, UnknownDependency, UrgencyConfig, and more. The whole engine is cronoq::core.

FeatureDefaultEffect
otelonOpenTelemetry metrics and W3C trace-context propagation (metrics reference).
store-codecoffThe cronoq::codec module: conversions between engine types and the form durable stores keep, shared by the Postgres and SQLite stores. Needed only to write a store.

cronoq-core

Core<P> is a deterministic state machine with no I/O, threads or clocks. Every method takes the current Time, so tests and simulations run thousands of virtual hours per second.

MethodDescription
Core::new(CoreConfig)Create; CoreConfig::validate() reports problems without panicking.
submit, try_submit, submit_batchAdmission.
complete(now, lease, Outcome), heartbeat(now, lease)Attempt feedback.
cancel, status, resolve, live_tasks, list_tasks, totalsLookups and cancellation.
set_capacity(now, pool, n), set_group_capacity(now, pool, labels, n)Capacity changes, for the whole pool or for the workers with exactly labels.
add_recurring, remove_recurring, recurring_names, list_recurringCron schedules.
tick(now), next_wakeup()Timers.
poll_action(), drain_actions(), has_actions()Action::{Dispatch, Abort, ScaleTo, Status, Persist, SpaceAvailable} for the driver.
snapshot(now)Metrics.
recover(now, Recovered)Restore state loaded from a store.
check_invariants()Panics on internal inconsistency (tests and fuzzing).

CoreConfig fields: pools, resources, priority, urgency, global_bounds, retention, retention_max, persist, epoch_unix_nanos, id_epoch, id_shard (default None; when set, task ids carry the shard number in their top 8 bits), metrics_window (default 60 s), seed.

cronoq-store-postgres

ItemDescription
PgStore::connect(url) / connect_with(url, PgStoreConfig)Connect and migrate.
PgStoreConfigschema (default public), retention, lock_poll, keepalive, session_timeout, commit_timeout, max_connections.
migrate()Apply pending schema migrations (versioned in cronoq_schema_version).
get_task(target)Read a stored task (TaskRecord). Also available through the cronoq::StoreQueries trait, with prune, list_finished, is_leader and leadership_lost.
list_finished(pools, statuses, after, limit)Finished tasks in id order, filtered by pool and status (any if empty), with ids above after.
prune(older_than)Delete finished tasks older than the given age.
is_leader(), epoch(), leadership_lost().await, release_leadership().awaitLeadership state.

cronoq-store-sqlite

ItemDescription
SqliteStore::open(path) / open_with(path, SqliteStoreConfig)Open (creating if needed) and migrate.
SqliteStoreConfigretention, lease_ttl (10 s), lease_renew (2 s), lock_poll, busy_timeout, commit_timeout, full_sync (default on), max_connections.
get_task, prune, list_finished, is_leader(), epoch(), leadership_lost().await, release_leadership().awaitAs for the Postgres store.

See Durability and high availability.

cronoq-server::worker

use cronoq_server::worker::{WorkerOptions, run_worker};

let opts = WorkerOptions::new("http://127.0.0.1:7070", "default").slots(8).token(token);
run_worker(opts, |lease| async move { Ok(lease.payload) }, shutdown_signal).await?;
WorkerOptions fieldDefaultDescription
endpoint, poolrequiredServer URL (http:// or https://) and pool name.
slots1Concurrent leases requested (the server may grant fewer).
tokennoneBearer token with the worker role.
nameemptyShown in server logs.
tlsnoneWorkerTls { ca_pem, identity, domain } for TLS and mTLS. Needs an https:// endpoint; with http:// the worker returns an error.
labelsemptyWorker labels, as (name, value) pairs; add one with the builder method label(name, value). Tasks that require labels are leased only to workers that have them.
reconnecttrueReconnect with backoff when the connection drops or the server steps down.
insecure_redirect_httpfalseFollow a shard redirect to plain http:// on another host with the token. Redirects otherwise keep TLS and use plain http only on loopback; see Sharding.
initial_backoff, max_backoff200 ms, 10 sReconnect backoff bounds.
drain_timeout30 sHow long running handlers may finish after shutdown resolves.
max_message_bytes64 MiBLargest message accepted from the server.

The handler receives a LeaseInfo (lease, task_id, attempt, pool, payload, content_type, kind, key, tags, timeout, deadline, cancel) and returns Result<Bytes, TaskError>. run_worker enforces the granted slots, heartbeats each lease, cancels lease.cancel on Abort, turns a panicking handler into a retryable failure, and returns an error only for problems retrying cannot fix (bad credentials, unknown pool).