Ferrite Queues deliver work to competing consumers without losing a message when a process exits. A consumer holds a time-bounded lease and acknowledges only after the domain effect is durable.
Declare and consume a queue
{
"services": [{ "name": "emails", "primitive": "queue" }],
"applications": [{
"name": "email-worker",
"artifact_key": "apps/email-worker@v1",
"artifact_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
"bindings": [
{ "handle": "emails", "kind": "queue", "service": "emails" }
]
}]
}
let mut emails = ctx.queue("emails")?;
loop {
let Some(lease) = emails.poll_wait(1_000).await? else { continue };
send_email_idempotently(&lease.payload).await?;
emails.ack(lease.token).await?;
}
If the process exits before ack, the lease expires and another consumer can
receive the work. Your effect must therefore be idempotent.
Delay and retry work
Delayed publish makes a message visible at a future timestamp. Use it for reminders, reservation expiry, and backoff. Attempt budgets bound repeated failure; exhausted work moves to a dead-letter queue where you can inspect and redrive it deliberately.
Scale consumers
ferrite dev --instances 3
ferrite dev --instances 3 --chaos 5
The first command runs three competing consumers. The second repeatedly kills them so you can verify redelivery and idempotency before production.
Delivery semantics
Ferrite makes the queue decision durable and duplicate-safe. It cannot make an arbitrary external side effect exactly once. Persist a provider event ID or idempotency record, use the provider’s idempotency key when available, and acknowledge only after you can prove the effect.