Correct usage of `ic_cdk::spawn`

Would it be possible to have someone explain to me the lifetime of a future driven by ic_cdk::spawn within a canister. Does the future continue processing after a reply has been given potentially consuming all the cycles for an invocation? Or, does it suspend at some point?

What I’d like to do is use ic_cdk::spawn to spawn call futures which will “eventually” be woken up by call responses. Something like…

async fn do_call() -> () {
    match ic_cdk::api::call::call_raw(.., .., .., ..).await {
        Ok(_) => {
            // continue something
        }
        Err(_) => {
            // maybe dead letter queue, maybe fail
        }
    }
}

ic_cdk::spawn(do_call());

spawn takes a future and drives it to completion; it doesn’t matter whether you replied already.
One quirk is that the spawn will call poll immediately and execute as much work as possible until it hits the first call. In other words,

spawn(async { expensive_sync_computation() });

is equivalent to

expensive_sync_computation();

This means you cannot use spawn alone to spread out work, you also need to initiate calls to self or other canisters.

In your example, the first thing you do is initiating a call, so spawn should work fine for your use-case.

3 Likes