Scheduling, priority & queues

Copy Markdown View Source

When an instance runs

By default an instance is runnable immediately. Delay it with any of:

GenDurable.insert(Report, schedule_in: 60_000)                       # ms from now
GenDurable.insert(Report, schedule_at: ~U[2026-07-01 09:00:00Z])     # a DateTime
GenDurable.insert(Report, eligible_at: ~U[2026-07-01 09:00:00Z])     # explicit column value

Precedence is :eligible_at:schedule_at:schedule_in. Within a step, {:retry, state, delay_ms} schedules the next attempt the same way (the poll/backoff primitive).

There is no built-in cron. Drive recurring work from your existing scheduler (a k8s CronJob, a cloud scheduler, or any timer) by calling insert/2 — and make it safe against double-firing for free by giving each occurrence a time-bucketed correlation_key: a duplicate fire is rejected as {:error, :duplicate}.

GenDurable.insert(DailyReport, correlation_key: "daily-report:#{Date.utc_today()}")

Priority

Lower number = earlier. Within a queue, the picker orders by (priority, eligible_at).

GenDurable.insert(Urgent, priority: 0)
GenDurable.insert(Bulk,   priority: 10)

Queues

A queue is a logical pool with its own concurrency limit. Configure them at start; an instance picks its queue from the FSM's :queue option or a per-instance :queue.

{GenDurable, repo: MyApp.Repo, queues: [default: 10, checkout: 5, email: 50]}

GenDurable.insert(SendEmail, queue: "email")

concurrency is the maximum number of steps that queue runs at once on a node. See the feeder knobs for tuning prefetch and poll behaviour, and concurrency keys for per-key serialization within a queue.