Persistent Sleep

Persistent or durable sleep means the workflow's state is saved, and execution will resume after the duration has elapsed, even if the Obelisk server restarts.

The Runtime Support API contains method sleep which creates an one-off Join Set and blocks the execution until the delay has timed out.

If the durable sleep is cancelled, sleep returns an error that must be handled by the workflow. See Cancellation for how delay cancellation fits into structured concurrency:

workflow_support::sleep(ScheduleAt::In(SchedulingDuration::Seconds(10)), None)
    .map_err(|()| MyWorkflowError::Cancelled)?;

The trailing None names the one-off join set (a name is optional).

Another way to submit a persistent delay is to use Heterogenous Join Set with the submit_delay function.

fn two_delays_in_same_join_set() -> Result<(), ()> {
    let join_set = workflow_support::join_set_create();
    let _long = submit_delay(&join_set, ScheduleAt::In(DurationEnum::Seconds(10)));
    let short = submit_delay(&join_set, ScheduleAt::In(DurationEnum::Milliseconds(10)));
    // child executions can be added to this join set using `-submit` extension.
    // `join_next` returns the completed value directly:
    // `result<result<option<string>, option<string>>, join-next-error>`.
    let res = join_next(&join_set)
        .expect("submitted two delays, joining first, thus `join-next-error::all-processed` cannot happen");
    assert!(res.is_ok()); // Ok(None) for an expired delay
    // Read which response was processed from `join_set.last_id()`.
    let Some(ResponseId::DelayId(first)) = join_set.last_id() else {
        unreachable!("only delays have been submitted");
    };
    assert_eq!(short.id, first.id);
    // long delay will be cancelled when the join set is closed.
    Ok(())