Wait for Event
ctx.wait_for_event() suspends a workflow until an external system delivers a named event. The suspension is fully durable — the execution can survive unlimited process restarts while waiting.
In the Workflow
Section titled “In the Workflow”use zart::{TaskHandler, TaskContext, TaskError, Scheduler};use serde::{Deserialize, Serialize};use std::time::Duration;
#[derive(Deserialize, Serialize)]struct ApprovalPayload { approved: bool, reviewer: String, notes: Option<String>,}
async fn run( &self, ctx: &mut TaskContext<impl Scheduler>, data: OrderData,) -> Result<(), TaskError> { // Process order steps... ctx.step("validate-order", || async { validate(&data).await }).await?;
// Wait up to 24 hours for manager approval let approval: ApprovalPayload = ctx.wait_for_event( "manager-approval", Some(Duration::from_secs(86400)), // 24h timeout ).await?;
if !approval.approved { return Err(TaskError::custom( format!("Order rejected by {}", approval.reviewer) )); }
// Fulfillment continues after approval... ctx.step("fulfill-order", || async { fulfill(&data).await }).await?;
Ok(())}Delivering the Event — Rust API
Section titled “Delivering the Event — Rust API”From anywhere in your application that has access to a DurableScheduler:
use zart::DurableScheduler;
// External system (e.g., a web handler) delivers the eventasync fn handle_approval_webhook( scheduler: &impl DurableScheduler, execution_id: &str, body: ApprovalPayload,) -> anyhow::Result<()> { scheduler.offer_event( execution_id, "manager-approval", serde_json::to_value(&body)?, ).await?; Ok(())}Delivering the Event — HTTP API
Section titled “Delivering the Event — HTTP API”When the HTTP API is available, deliver events via REST:
POST /api/v1/events/exec-abc-123/manager-approvalContent-Type: application/json
{ "approved": true, "reviewer": "jane@example.com", "notes": "Looks good, proceed."}Response:
{ "status": "delivered", "execution_id": "exec-abc-123", "event_name": "manager-approval"}Delivering the Event — CLI
Section titled “Delivering the Event — CLI”zart event exec-abc-123 manager-approval \ --data '{"approved":true,"reviewer":"jane@example.com"}'Timeout Behaviour
Section titled “Timeout Behaviour”If the timeout expires before the event is delivered, wait_for_event returns Err(TaskError::EventTimeout).
let result = ctx.wait_for_event::<ApprovalPayload>( "approval", Some(Duration::from_secs(3600)),).await;
match result { Ok(payload) => { /* event received */ } Err(TaskError::EventTimeout) => { // Auto-approve, cancel, or escalate ctx.step("auto-escalate", || async { escalate_to_vp(&data.order_id).await }).await?; } Err(e) => return Err(e),}To wait indefinitely, pass None as the timeout:
// No timeout — waits foreverlet payload: MyPayload = ctx.wait_for_event("confirm", None).await?;Use Cases
Section titled “Use Cases”Human-in-the-Loop Approval
Section titled “Human-in-the-Loop Approval”Pause a workflow pending review by a human. Resume it when they click “Approve” in your UI.
let approval: ReviewDecision = ctx.wait_for_event( "review-decision", Some(Duration::from_secs(7 * 86400)), // 1 week).await?;Webhook Response
Section titled “Webhook Response”Call an external API asynchronously and wait for a webhook callback:
// Step 1: trigger the async joblet job_id: String = ctx.step("trigger-job", || async { external_api.start_job(&data).await}).await?;
// Step 2: wait for their webhook to call back with the resultlet result: JobWebhookPayload = ctx.wait_for_event( &format!("job-complete-{job_id}"), Some(Duration::from_secs(3600)),).await?;Your webhook endpoint then calls scheduler.offer_event(exec_id, &event_name, payload).
Two-Factor Authentication
Section titled “Two-Factor Authentication”Pause account actions until the user confirms via email or SMS:
ctx.step("send-2fa-code", || async { sms.send_code(&data.phone, &code).await}).await?;
let _: TwoFactorConfirm = ctx.wait_for_event( "2fa-confirmed", Some(Duration::from_secs(600)), // 10 minute window).await?;Waiting for External Job Completion
Section titled “Waiting for External Job Completion”Integrate with systems that notify you when work is done rather than polling:
// Start a long-running ML training joblet run_id: String = ctx.step("start-training", || async { ml_platform.start_training_run(&data.config).await}).await?;
// Wait for the platform to POST back when training finisheslet metrics: TrainingMetrics = ctx.wait_for_event( "training-complete", Some(Duration::from_secs(6 * 3600)), // 6 hour max).await?;
println!("Accuracy: {:.2}%", metrics.accuracy * 100.0);Multiple Events in Sequence
Section titled “Multiple Events in Sequence”You can call wait_for_event multiple times in a single workflow:
// First: payment authorizationlet auth: PaymentAuth = ctx.wait_for_event( "payment-authorized", Some(Duration::from_secs(900)),).await?;
// Process payment...
// Second: shipment confirmationlet tracking: ShipmentInfo = ctx.wait_for_event( "order-shipped", Some(Duration::from_secs(5 * 86400)),).await?;
println!("Tracking: {}", tracking.tracking_number);