Queues
See the queues tutorial for how to use these. Full API documentation is on docs.rs.
Managing Queues
A queue's configuration is stored in the system database, so these are methods of a launched DBOS, and of Client.
Every worker re-reads a queue's configuration as it polls, so a change takes effect across the fleet without a restart.
register_queue
impl DBOS {
pub async fn register_queue(
&self,
name: &str,
options: QueueOptions,
on_conflict: QueueConflict,
) -> dbos::Result<Queue>;
}
Create a queue, or report the one already registered under name, and return its stored configuration.
Call it after launch; before, it returns Error::NotLaunched.
Each queue belongs to the application that registers it, and only that application dequeues from it.
Parameters:
- name: The queue's name.
- options: Its
QueueOptions. - on_conflict: What to do if the queue exists.
QueueConflict:UpdateIfLatestVersion: overwrite the stored options only if this process runs the application's latest version, so an old version still running during a rolling deploy doesn't revert the new one's settings. The usual choice at startup. AClientcan't use it.AlwaysUpdate: always overwrite them.NeverUpdate: keep what is stored.
let queue = dbos.register_queue(
"task_queue",
QueueOptions { worker_concurrency: Some(5), ..QueueOptions::default() },
QueueConflict::UpdateIfLatestVersion,
).await?;
queue
pub async fn queue(&self, name: &str) -> dbos::Result<Option<Queue>>;
pub async fn list_queues(&self) -> dbos::Result<Vec<Queue>>;
The stored configuration of one queue, or of every queue the application owns.
A Queue has name(), concurrency(), worker_concurrency(), rate_limit(), is_partitioned(), partition_concurrency(), partition_worker_concurrency(), partition_rate_limit() and polling_interval().
update_queue
pub async fn update_queue(&self, name: &str, change: QueueChange) -> dbos::Result<Queue>;
Change some of a queue's options and return the result.
QueueChange has a field per option, each a Change: Change::Leave (the default) keeps the stored value, Change::Set(value) replaces it.
dbos.update_queue("task_queue", QueueChange {
concurrency: Change::Set(Some(50)),
..QueueChange::default()
}).await?;
delete_queue
pub async fn delete_queue(&self, name: &str) -> dbos::Result<()>;
Remove a queue's registration. Removing one that isn't registered is not an error. Workflows already enqueued on it are left in place and aren't dequeued until the queue is registered again, so pause a queue with a concurrency of 0 instead.
QueueOptions
pub struct QueueOptions {
pub concurrency: Option<i32>,
pub worker_concurrency: Option<i32>,
pub polling_interval: Duration,
pub rate_limit: Option<RateLimit>,
pub partition_concurrency: Option<i32>,
pub partition_worker_concurrency: Option<i32>,
pub partition_rate_limit: Option<RateLimit>,
}
Build with ..QueueOptions::default().
- worker_concurrency: The most of the queue's workflows one process runs at once. Default:
None.Some(0)pauses the queue on every executor. It can't be belowpartition_worker_concurrency, which must be at least 1, so to pause a queue that sets one, clearpartition_worker_concurrencyin the same update. - concurrency: The most that run at once across all processes, counting every
PENDINGworkflow on the queue, including older versions'. Default:None. It can't be belowworker_concurrencyor a per-partition concurrency limit, which must be at least 1, soSome(0)pauses the queue only whenworker_concurrencyis 0 or unset and no per-partition concurrency limit is set. - rate_limit: At most
RateLimit{ limit, period }starts in anyperiod, across all processes. Default:None. - partition_concurrency, partition_worker_concurrency, partition_rate_limit: The same limits per partition key. Setting any of them partitions the queue; queue-wide limits on a partitioned queue are enforced too.
- polling_interval: How often a quiet queue is polled. Default: 1 second.
Enqueueing
A workflow this process registered is enqueued by starting it with a QueueRequest in StartOptions::queue.
A workflow it doesn't have is enqueued by name with DBOS::enqueue, or from another application with Client::enqueue.
Enqueued from inside a workflow, by either route, the enqueued workflow is a child of the caller, recorded at the caller's step.
Queued workflows are dequeued in priority order, then first in, first out.
QueueRequest
pub struct QueueRequest<'a> {
pub name: &'a str,
pub deduplication_id: Option<&'a str>,
pub priority: Option<u32>,
pub partition_key: Option<&'a str>,
pub delay: Option<Duration>,
pub duplication_policy: DuplicationPolicy,
pub serialization: SerializationFormat,
}
impl<'a> QueueRequest<'a> {
pub fn new(name: &'a str) -> Self;
}
A queue to enqueue a workflow on, and what to ask of it. Build with QueueRequest::new(name) and struct update syntax.
- name: The queue.
- deduplication_id: While a workflow with this ID is enqueued or running on the queue, another enqueue with it is refused. Default:
None. - duplication_policy: What a refused enqueue does.
DuplicationPolicy::Reject(default) fails withdbos::sysdb::Error::QueueDeduplicated;ReturnExistingreturns a handle to the workflow holding the ID, discarding this call's input.ReturnExistingneeds adeduplication_id. - priority: From 1 to 2,147,483,647; lower is dequeued first. Default:
None, which is dequeued before any priority.Some(0)is refused. - partition_key: The workflow's partition on a partitioned queue. A workflow enqueued on a partitioned queue without one is never dequeued; on other queues the key is ignored. A deduplication ID applies across the whole queue, not per partition.
- delay: Hold the workflow
DELAYEDthis long before it can be dequeued, on the database's clock. Default:None. - serialization: A
SerializationFormatfor the workflow's input and output.
enqueue
impl DBOS {
pub fn enqueue<'a, P: Serialize, R, E>(&self, workflow: impl Into<QualifiedWorkflowName>, queue: &'a str, input: P) -> PendingStart<'a, R, E>;
pub fn enqueue_with<'a, P: Serialize, R, E>(&self, workflow: impl Into<QualifiedWorkflowName>, input: P, options: EnqueueOptions<'a>) -> PendingStart<'a, R, E>;
pub fn enqueue_portable<'a, R, E>(&self, workflow: impl Into<QualifiedWorkflowName>, args: PortableWorkflowArgs, options: EnqueueOptions<'a>) -> PendingStart<'a, R, E>;
}
Enqueue a workflow by name, for a workflow this process needn't have: one another service implements, possibly in another language.
The name isn't looked up locally; whichever executor has the workflow dequeues it.
The type parameters state the workflow's result and error types; nothing checks them until the result is decoded.
enqueue_portable passes a PortableWorkflowArgs (positional_args, named_args) as given, for a workflow in another language that takes named arguments.
let handle: WorkflowHandle<String> = dbos.enqueue("send_email", "email-queue", "hello").await?;
EnqueueOptions
pub struct EnqueueOptions<'a> {
pub queue_name: &'a str,
pub deduplication_id: Option<&'a str>,
pub duplication_policy: DuplicationPolicy,
pub priority: Option<u32>,
pub partition_key: Option<&'a str>,
pub delay: Option<Duration>,
pub serialization: SerializationFormat,
pub workflow_id: Option<&'a str>,
pub workflow_id_reuse_policy: WorkflowIdReusePolicy,
pub app_name: Option<&'a str>,
pub app_version: Option<&'a str>,
pub timeout: Timeout,
pub attributes: Option<&'a serde_json::Map<String, serde_json::Value>>,
}
impl<'a> EnqueueOptions<'a> {
pub fn new(queue_name: &'a str) -> Self;
}
Options for an enqueue by name. The queue fields mean what they mean on a QueueRequest. In addition:
- workflow_id, workflow_id_reuse_policy: As for a start.
- app_name: The application that implements the workflow. Default: this application for
DBOS::enqueue_with, the client'sapp_nameforClient::enqueue_with. A client with neither writes an unclaimed workflow, which any application may run. - app_version: The version that must run it. Default:
None, which the application's latest version dequeues. - timeout: The workflow's
Timeout. FromDBOS::enqueue_withinside a workflow,Inherittakes the caller's deadline. - attributes: Attributes recorded with the workflow.