Task queues and schedules for MoonBit: workers, retries, periodic beats, and the chain, group and chord canvas. Brokers and result stores are separate modules.
let now = fn() { @env.now() }
let broker = @moontask.MemoryBroker::new(clock=now)
let app = @moontask.App::new(broker, backend=broker, counter=broker, clock=now)
let greet = app.task("greet", fn(name : String, ctx : @moontask.Context) {
"hello \{name}, attempt \{ctx.attempt}"
})
let worker = app.worker(concurrency=4)
@async.with_task_group(async fn(group) {
group.spawn_bg(async fn() { worker.run() }, no_wait=true)
let handle = greet.send("ada")
println(handle.get(timeout=5000L))
worker.stop()
})| Package | What it is |
|---|---|
| moontask/spec | The contracts — Broker, Backend, Counter, Inspector — and the message, outcome and state they carry |
| moontask | App, Task, Handle, Worker, Beat, the canvas, and an in-memory broker that is also a store and a counter |
| moontask/schedule | A job on a rhythm inside one process, with no broker behind it |
| moontask/wait | The one place a wait is written, so the WebAssembly targets are handled once |
| Module | What it is |
|---|---|
| moontask-redis | A broker and result store on Redis, with per-consumer leases and recovery of a worker that stopped — or on Celery's own key layout, so one queue can be shared with a Celery worker |
| moontask-admin | A management interface as an ASGI application: a page, reports, sending, revoking, and a live stream of counts |
| Field | Meaning | Default |
|---|---|---|
| queue | Where the message goes | "default" |
| retries | How many times a failed run is tried again | 0 |
| backoff | The wait between attempts | exponential, 1s base, 10min cap, jittered |
| timeout | How long one run may take | no limit |
| acks_late | Confirm after the run instead of on receipt | false |
| ignore_result | Keep no result | false |
| rate | Runs per window, per worker | no limit |
let chained = @moontask.chain([step.sig(1), step.sig(2), step.sig(3)]).send(app) // answers the last
let grouped = @moontask.group([step.sig(4), step.sig(5)]).send(app) // answers a list
let joined = @moontask.chord([step.sig(1), step.sig(2), step.sig(3)], total.sig([])).send(app)let beat = app.beat()
beat.add("tick", tick, (), @moontask.Schedule::Every(interval=1000L))
beat.add("nightly", report, (), @moontask.Schedule::Cron(expr~))let conn = @socket.Connection::connect(@moonredis.ClientOptions::at("127.0.0.1", 6379))
let broker = @redis.Broker::new(conn, clock=now, consumer="worker-7")
let app = @moontask.App::new(broker, backend=broker.store(), counter=broker.store(), clock=now)let broker = @redis.Broker::celery(conn, clock=now, consumer="worker-7")| the queue | the list named after it, split across Celery's priority steps |
| the payload | Celery's envelope: task and id in headers, arguments in the body |
| what a consumer holds | Celery's unacked hash and its index, so either side can hand back a claim the other left |
| a chain | each message carries the rest of its chain; a link that is not immutable is called with the previous link's result prepended |
| a chord | the parts' results land in Celery's join keys as they settle, so the last part — on either side — closes it |
| an eta | the message sits on the queue and the consumer holds it, which is what Celery does |
pub(open) trait Broker {
async fn publish(Self, queue : String, message : Message) -> Unit raise Refused
async fn consume(Self, queues : ArrayView[String], prefetch~ : Int32) -> Delivery raise Refused
async fn ack(Self, delivery : Delivery) -> Unit raise Refused
async fn reject(Self, delivery : Delivery, requeue~ : Bool) -> Unit raise Refused
}moon run src/examples/01-queue
moon run src/examples/02-canvastype Limiterimpl Backend for MemoryBrokerimpl Broker for MemoryBrokerasync fn consume(self : MemoryBroker, queues : ArrayView[String], prefetch~ : Int) -> Delivery raise Refusedimpl Counter for MemoryBrokerasync fn settle(self : MemoryBroker, chord : Chord, id : String, outcome : Outcome) -> ChordState raise Refusedimpl Inspector for MemoryBrokerasync fn MemoryBroker::consume(self : MemoryBroker, queues : ArrayView[String], prefetch~ : Int) -> Delivery raise Refusedasync fn MemoryBroker::peek(self : MemoryBroker, queue : String, limit~ : Int) -> Array[Message] raise Refusedasync fn MemoryBroker::publish(self : MemoryBroker, queue : String, message : Message) -> Unit raise Refusedasync fn MemoryBroker::reject(self : MemoryBroker, delivery : Delivery, requeue~ : Bool) -> Unit raise Refusedasync fn MemoryBroker::settle(self : MemoryBroker, chord : Chord, id : String, outcome : Outcome) -> ChordState raise Refusedasync fn MemoryBroker::store(self : MemoryBroker, id : String, outcome : Outcome) -> Unit raise Refusedtype RegisteredInstall
Download zipTask queues and schedules for MoonBit: workers, retries, periodic beats, and the chain, group and chord canvas. Brokers and result stores are separate modules.