pub fn chain(Array[Sig]) -> Sig
| The runs in sigs, in order, each one started when the one before it succeeds.
A chain of chains is flattened, so chain([a, chain([b, c])]) is a → b → c. Building a chain publishes nothing.
Every public item of the module, generated from the interfaces moon info writes.
pub fn chain(Array[Sig]) -> Sig
| The runs in sigs, in order, each one started when the one before it succeeds.
A chain of chains is flattened, so chain([a, chain([b, c])]) is a → b → c. Building a chain publishes nothing.
pub fn chord(Array[Sig], Sig) -> Sig
| The runs in parts, then callback once every part has succeeded.
The callback is sent with the list of part results as its argument, in the order the parts were given. Every part carries the same key and the same list of ids, so the part that finishes last can collect the set by itself.
A part that fails for good does not hold the chord open: the last part to finish records the callback as failed, so nobody waits on a callback that will never be sent.
pub fn group(Array[Sig]) -> Sig
| Every run in sigs, all at once, waited on together.
A chain given to a group is not broken up: its head is published and its tail travels with it, so the group waits on the chain's last link. The handle's value is the list of results in the order the sigs were given.
pub fn milliseconds_of(@moondate.Moment) -> Int64?
| Milliseconds since the epoch of an instant.
pub fn moment_of(Int64) -> @moondate.Moment?
| An instant from milliseconds since the epoch.
pub let policy : Policy
| The defaults, documented field by field on [Policy].
pub struct App {
broker&@spec.Brokerbackend&@spec.Backend?counter&@spec.Counter?clock() -> Int64tasksMap[String, Registered]runningMap[String, @async.Task[Result[@json.Json, String]]]mut seq : Int32}| The object every other type hangs off.
It owns the three seams (broker, result store, chord counter), the clock the library reads instead of the system clock, and the registry that turns a message name back into a body. Nothing here is global: two apps in one process do not see each other's tasks.
pub fn App::backend_of(Self) -> &@spec.Backend?
| The result store the app was given, or None when it keeps nothing.
pub fn App::beat(Self) -> Beat
| A beat on app with nothing scheduled.
pub fn App::has_task(Self, String) -> Bool
| Whether a body is registered under name.
pub fn App::new(&@spec.Broker, backend? : &@spec.Backend, counter? : &@spec.Counter, clock~ : () -> Int64) -> Self
| An app on broker, with backend keeping results, counter counting chord parts, and clock as the only source of time.
The store and the counter are optional: an app without a store runs tasks nobody waits on, and an app without a counter refuses to build a chord. A broker that also implements Backend and Counter — the in-memory one and the Redis one both do — is passed three times.
pub fn App::now(Self) -> Int64
| The app's time, in milliseconds since the epoch.
pub fn App::policy_of(Self, String) -> Policy?
| The policy registered under name, or None when nobody registered it.
pub async fn App::send(Self, String, @json.Json, eta? : Int64, countdown? : Int64, expires? : Int64, queue? : String, priority? : Int32, id? : String) -> Handle[@json.Json] raise @spec.Refused
pub fn[A : @json.FromJson, R : @json.ToJson] App::task(Self, String, async (A, Context) -> R, policy? : Policy) -> Task[A, R]
| Register run under name and return the task a caller sends.
Registering twice under the same name replaces the first, which is what makes it possible to run the same task under two policies in one test.
pub fn App::task_names(Self) -> Array[String]
| Every registered name, sorted so a page listing them is stable.
pub fn App::worker(Self, queues? : Array[String], concurrency? : Int32, prefetch? : Int32) -> Worker
| A worker over queues that runs up to concurrency tasks at once.
prefetch is how many messages one worker may hold unsettled: a worker that holds more than it can run looks busy while the queue behind it starves.
pub fn Backoff::delay(Self, Int32, String) -> Int64
| The wait before attempt attempt, counting the first attempt as one.
seed is what the spread is derived from: the task id in practice. Attempt zero never waits, since nothing has failed yet.
pub fn Backoff::equal(Self, Self) -> Bool
pub fn Backoff::not_equal(Self, Self) -> Bool
pub fn Backoff::to_repr(Self) -> @debug.Repr
pub struct Beat {
appAppentriesArray[BeatEntry]mut stopping : Bool}| The object that sends tasks on a schedule.
A beat holds a list of entries and, every tick, sends the ones whose time has come. It keeps the phase: a schedule of every hour fires at the same minute every hour even if one tick ran late, because the next time is computed from the time that was due, not from the time the tick happened.
pub fn[A : @json.ToJson, R] Beat::add(Self, String, Task[A, R], A, Schedule) -> Unit
| Schedule task with args under name.
The name identifies the entry, not the task: the same task may be scheduled twice under two names and two schedules.
pub fn Beat::pending(Self) -> Array[(String, Int64)]
| The entry names and when each fires next, soonest first.
pub async fn Beat::run(Self) -> Unit raise @spec.Refused
pub fn Beat::stop(Self) -> Unit
| Stop after the tick in progress.
pub fn Context::equal(Self, Self) -> Bool
pub fn Context::not_equal(Self, Self) -> Bool
pub fn Context::to_repr(Self) -> @debug.Repr
pub struct Handle[R] {
appAppidsArray[String]allBoolcodec(@json.Json) -> R raise @spec.Refused}| A run, or a set of runs, a caller can wait on and look at.
The result type is the one the task returns: get decodes the stored JSON back into it. state and revoke work on anything, since a caller that wants to cancel a run does not care what it would have returned.
pub async fn[R] Handle::get(Self[R], timeout? : Int64) -> R raise @spec.Refused
pub fn[R] Handle::ids(Self[R]) -> Array[String]
| The ids the handle waits on.
pub fn[R : @json.FromJson] Handle::of(App, Array[String], Bool) -> Self[R]
| A handle over ids whose value decodes into R; all makes get answer the list of results in the order of ids.
pub fn Handle::of_json(App, Array[String], Bool) -> Self[@json.Json]
| A handle over ids of runs that already answer in JSON.
pub async fn[R] Handle::revoke(Self[R], terminate? : Bool) -> Unit raise @spec.Refused
pub async fn[R] Handle::state(Self[R]) -> @spec.State raise @spec.Refused
pub struct MemoryBroker {
clock() -> Int64lock@async.MutexqueuesMap[String, Array[@spec.Message]]mut delayed : Array[@spec.Message]unackedMap[String, @spec.Delivery]resultsMap[String, @spec.Outcome]countersMap[String, Int32]deadArray[@spec.Message]mut seq : Int32}| A broker, result store, chord counter and inspector over maps.
clock is the same function the app is given: the broker needs time to know when a delayed message is due, and the library never reads the system clock itself.
pub async fn MemoryBroker::ack(Self, @spec.Delivery) -> Unit raise @spec.Refused
pub async fn MemoryBroker::add(Self, String, Int32) -> Int32 raise @spec.Refused
pub async fn MemoryBroker::consume(Self, ArrayView[String], prefetch~ : Int32) -> @spec.Delivery raise @spec.Refused
pub async fn MemoryBroker::drop(Self, String) -> Unit raise @spec.Refused
pub async fn MemoryBroker::fetch(Self, String) -> @spec.Outcome? raise @spec.Refused
pub fn MemoryBroker::new(clock~ : () -> Int64) -> Self
| An empty broker whose time comes from clock.
pub async fn MemoryBroker::peek(Self, String, limit~ : Int32) -> Array[@spec.Message] raise @spec.Refused
pub async fn MemoryBroker::publish(Self, String, @spec.Message) -> Unit raise @spec.Refused
pub async fn MemoryBroker::queues(Self) -> Array[@spec.QueueInfo] raise @spec.Refused
pub async fn MemoryBroker::reject(Self, @spec.Delivery, requeue~ : Bool) -> Unit raise @spec.Refused
pub async fn MemoryBroker::settle(Self, @spec.Chord, String, @spec.Outcome) -> @spec.ChordState raise @spec.Refused
pub async fn MemoryBroker::store(Self, String, @spec.Outcome) -> Unit raise @spec.Refused
pub impl @spec.Backend for MemoryBroker
pub impl @spec.Broker for MemoryBroker
pub impl @spec.Counter for MemoryBroker
pub impl @spec.Inspector for MemoryBroker
pub fn Policy::backoff_delay(Self, Int32, String) -> Int64
| The wait before attempt attempt of a task whose id is seed.
pub fn Policy::equal(Self, Self) -> Bool
pub fn Policy::not_equal(Self, Self) -> Bool
pub fn Policy::to_repr(Self) -> @debug.Repr
pub fn Rate::equal(Self, Self) -> Bool
pub fn Rate::not_equal(Self, Self) -> Bool
pub fn Rate::to_repr(Self) -> @debug.Repr
pub fn Schedule::after(Self, Int64) -> Int64?
| The first time this schedule fires strictly after at, or None when it never fires again.
pub fn Schedule::equal(Self, Self) -> Bool
pub fn Schedule::first(Self, Int64) -> Int64
| The first time this schedule fires at or after now.
pub fn Schedule::not_equal(Self, Self) -> Bool
pub fn Schedule::to_repr(Self) -> @debug.Repr
pub fn Shape::equal(Self, Self) -> Bool
pub fn Shape::not_equal(Self, Self) -> Bool
pub fn Shape::to_repr(Self) -> @debug.Repr
pub struct Sig {
publishArray[@spec.Message]waitsArray[String]shapeShape}| A piece of work that has not been published yet.
The messages are ready to go; waits is what a caller waits on afterwards, which for a chain is its last link and for a chord is the callback. Building a sig publishes nothing, so a canvas can be built once and sent twice.
pub fn Sig::links(Self) -> Array[@spec.Message]
| Every message this sig stands for, in the order they run: the links of a chain, the parts of a group.
pub async fn Sig::send(Self, App) -> Handle[@json.Json] raise @spec.Refused
pub struct Task[A, R] {
appAppnameStringpolicyPolicyrunasync (A, Context) -> R}| A registered body. Sending it writes a message and hands back a handle.
The argument type is what the body takes; the result type is what it returns, and the handle decodes the stored value back into it. Both go over the wire as JSON, so a task may be sent by one process and run by another.
pub fn[A, R] Task::name(Self[A, R]) -> String
| The name the message carries.
pub fn[A, R] Task::policy(Self[A, R]) -> Policy
| The policy the registration was given.
pub async fn[A : @json.ToJson, R : @json.FromJson] Task::send(Self[A, R], A, eta? : Int64, countdown? : Int64, expires? : Int64, queue? : String, priority? : Int32, id? : String) -> Handle[R] raise @spec.Refused
pub fn[A : @json.ToJson, R] Task::sig(Self[A, R], A) -> Sig
| The run of args as a node of a canvas, without publishing it.
pub struct Worker {
appAppqueuesArray[String]concurrencyInt32prefetchInt32limitersMap[String, Limiter]consumersArray[@async.Task[Unit]]mut inflight : Int32mut stopping : Booldone@cond_var.Condmut failure : Error?}| The object that runs tasks.
A worker consumes from queues, runs up to concurrency bodies at once, and settles each message according to the task's policy: a failure within the retry budget goes back on the queue with an eta computed from the backoff, a success advances the chain or the chord the message carries.
stop is graceful: it stops taking new messages, waits up to grace milliseconds for the ones in flight, then cancels whatever is left.
pub fn Worker::is_stopping(Self) -> Bool
| Whether stop has been called.
pub fn Worker::prefetch(Self) -> Int32
| The most messages this worker holds unsettled at once.
pub fn Worker::queues(Self) -> Array[String]
| The queues this worker takes from.
pub async fn Worker::run(Self) -> Unit
pub async fn Worker::stop(Self, grace? : Int64) -> Unit
pub fn celery_group_key(String, String) -> String
| The keys a chord's join lives under in Celery's redis backend: the results as they arrive (.j, a sorted set scored by the part's index), the adjustment to the size (.t), and the size itself (.s).
pub fn celery_result_key(String) -> String
| The key Celery's result backend stores a run under.
pub fn outcome_failed(String, Int32, Int64) -> Outcome
| The outcome of a run that raised error on attempt retries.
pub fn outcome_succeeded(@json.Json, Int32, Int64) -> Outcome
| The outcome of a run that returned value.
pub fn Refused::equal(Self, Self) -> Bool
pub fn Refused::not_equal(Self, Self) -> Bool
pub fn Refused::output(Self, &Logger) -> Unit
pub fn Refused::to_repr(Self) -> @debug.Repr
pub fn Refused::to_string(Self) -> String
pub impl Show for Refused
pub fn Chord::equal(Self, Self) -> Bool
pub fn Chord::from_json(@json.Json, @json.JsonPath) -> Self raise @json.JsonDecodeError
pub fn Chord::not_equal(Self, Self) -> Bool
pub fn Chord::to_json(Self) -> @json.Json
pub fn Chord::to_repr(Self) -> @debug.Repr
pub impl @json.FromJson for Chord
pub impl @json.ToJson for Chord
pub fn Delivery::equal(Self, Self) -> Bool
pub fn Delivery::not_equal(Self, Self) -> Bool
pub fn Delivery::to_repr(Self) -> @debug.Repr
pub fn Message::equal(Self, Self) -> Bool
pub fn Message::from_celery(@json.Json, queue~ : String) -> Self raise Refused
| Read a Celery envelope back into a message.
queue is what the broker knows and the envelope names, so a message read off a list is told which list it came from.
pub fn Message::from_json(@json.Json, @json.JsonPath) -> Self raise @json.JsonDecodeError
pub fn Message::is_due(Self, Int64) -> Bool
| Whether the message may run at now: its eta, when set, has come.
pub fn Message::is_expired(Self, Int64) -> Bool
| Whether the message is past the time it may still run at now.
pub fn Message::new(String, String, @json.Json) -> Self
| A message for name with argument args, queued on default with no delay and no retries behind it.
pub fn Message::not_equal(Self, Self) -> Bool
pub fn Message::parse(StringView) -> Self raise Refused
| A message read from its JSON text. The FromJson impl is the same reading; this is the entry a broker uses, so a bad payload is refused in this library's terms rather than in the JSON module's.
pub fn Message::text(Self) -> String
| The JSON text of a message, which is what a broker stores.
pub fn Message::to_celery(Self) -> @json.Json
| The message as Celery's envelope, ready to be pushed on a queue.
pub fn Message::to_json(Self) -> @json.Json
pub fn Message::to_repr(Self) -> @debug.Repr
pub impl @json.FromJson for Message
pub impl @json.ToJson for Message
pub fn Outcome::equal(Self, Self) -> Bool
pub fn Outcome::from_celery(@json.Json) -> Self raise Refused
| An outcome read back from Celery's result backend.
pub fn Outcome::from_json(@json.Json, @json.JsonPath) -> Self raise @json.JsonDecodeError
pub fn Outcome::not_equal(Self, Self) -> Bool
pub fn Outcome::to_celery(Self, String) -> @json.Json
| An outcome as Celery's result backend writes it, so a Celery client waiting on AsyncResult reads what a worker here finished.
pub fn Outcome::to_json(Self) -> @json.Json
pub fn Outcome::to_repr(Self) -> @debug.Repr
pub impl @json.FromJson for Outcome
pub impl @json.ToJson for Outcome
pub fn QueueInfo::equal(Self, Self) -> Bool
pub fn QueueInfo::not_equal(Self, Self) -> Bool
pub fn QueueInfo::to_repr(Self) -> @debug.Repr
pub fn State::code(Self) -> String
| The label a result store writes for a state. These are the labels the published protocol uses, so a result written by another producer reads back as the same state.
pub fn State::equal(Self, Self) -> Bool
pub fn State::is_final(Self) -> Bool
| Whether no further state will follow. A caller waiting for a result stops here.
pub fn State::not_equal(Self, Self) -> Bool
pub fn State::of(StringView) -> Self raise Refused
| The state a store's label names. An unknown label is refused rather than read as Pending: a store that grew a state this library does not know is a store this library must not guess about.
pub fn State::output(Self, &Logger) -> Unit
pub fn State::to_repr(Self) -> @debug.Repr
pub fn State::to_string(Self) -> String
pub impl Show for State
pub fn every(Int64) -> Job
| A job every milliseconds, before a unit is chosen.
every(10).seconds() is ten seconds and every(10).minutes() is ten minutes; every(250) on its own is two hundred and fifty milliseconds.
pub struct Job {
nameStringintervalInt64anchorInt64action(async () -> Unit)?mut next : Int64mut runs : Int32mut failures : Int32}| One rhythm inside a process.
Built by [every] and refined in a chain: every(10).minutes() is ten minutes, .at(":30") puts it on the half minute, and .run(action) gives it something to do. The interval is kept in milliseconds, which is the unit the rest of this library uses; every(n) on its own is n milliseconds.
pub fn Job::at(Self, StringView) -> Self raise @spec.Refused
| Where in the period the run lands: ":30" is thirty seconds past the boundary, "15:30" fifteen minutes and thirty seconds past it, and "9:15:00" nine hours, fifteen minutes past it.
A time that does not fit the period is refused rather than rounded, since a rhythm that fires at a time it was not asked for is worse than one that does not start.
pub fn Job::days(Self) -> Self
| The interval read as days.
pub fn Job::failures(Self) -> Int32
| How many of those runs raised.
pub fn Job::hours(Self) -> Self
| The interval read as hours.
pub fn Job::interval(Self) -> Int64
| How long one period is, in milliseconds.
pub fn Job::minutes(Self) -> Self
| The interval read as minutes.
pub fn Job::name(Self) -> String
| The name of the job, job until one is given.
pub fn Job::named(Self, String) -> Self
| A name for the job, for a page that lists what is scheduled.
pub fn Job::next_after(Self, Int64) -> Int64
| The first time this job fires strictly after after.
The rhythm is anchored to the epoch and shifted by the job's offset, so a job every ten minutes at ":30" fires at 00:00:30, 00:10:30 and so on, whatever time it was added at. Strictly after is what makes a loop that has just fired ask for the run after it, rather than for the one it has just done.
pub fn Job::next_at(Self) -> Int64
| When the job runs next, in milliseconds since the epoch.
pub fn Job::run(Self, async () -> Unit) -> Self
| What the job does, and the job itself so the chain can continue.
pub fn Job::runs(Self) -> Int32
| How many times the job has run.
pub fn Job::seconds(Self) -> Self
| The interval read as seconds.
pub struct Scheduler {
clock() -> Int64jobsArray[Job]mut stopping : Bool}| A set of jobs and the clock they run against.
The scheduler holds no queue and no store: a job that must survive a restart, run on another machine, or be retried belongs on a task instead. What it does keep is the rhythm — the next run of each job is computed from the run that was due, not from the moment the loop happened to wake, so a loop that was busy for a while does not drag every job with it.
pub fn Scheduler::add(Self, Job) -> Unit
| Take job into the schedule, with its first run computed from now.
The job is held as it was given: changing it afterwards changes nothing, so build the chain before adding it.
pub fn Scheduler::new(clock~ : () -> Int64) -> Self
| A scheduler whose only source of time is clock.
pub fn Scheduler::pending(Self) -> Array[Job]
| Every job, soonest first, with how many times each has run.
pub async fn Scheduler::run(Self) -> Unit
pub fn Scheduler::stop(Self) -> Unit
| Stop after the run in progress. The loop wakes at least every 50 milliseconds, so this takes effect promptly even with nothing scheduled.
pub async fn nap(Int32) -> Unit noraise