Async calls on IC

I’ve got two questions regarding async calls in Rust.

  1. What happens if inter-canister update calls are not awaited by the sender? Can they be sent in a “send and forget” kind of way?
  2. Is it possible that no response at all is received during an inter-canister update call that is awaited? I have a case where I call another canister with ic_cdk::call() and await the response but I don’t seem to be receiving anything, not even an Err response from the CallResult or any timeout. Is that possible?

Rust futures (what you get from “calling” an async fn) don’t do anything unless you await them. They’re similar to defining something like let f = |i| println!("{}", i); and then never calling f(n). So that’s exactly what would happen with a canister call that you never await: it wouldn’t be made.

At the protocol level, every request produces a response, whether it’s a response from the callee; or a reject response from the system (e.g. “not enough cycles”).

You can have your request handler produce a response before you’ve awaited all (or any of) the calls you made. But in order for the calls to be made at all, you need to await them. And if you do make / await them, the call context will be open until they all produce a response.

1 Like

Thanks for the clarification!

  1. Ok, this makes sense and helps.
  2. I’ve figured out the problem on my end. I didn’t define the expected Reponse payload correctly because I was missing one element of an enum type and it caused the call to fail and the entire execution to trap.

Note that there’s also ic_cdk::notify if you don’t want to await.

1 Like

Indeed. My knowledge of the CDK is rather limited and it shows.

Do note, however, that while ic_cdk::notify will (try to) deliver a request to the callee without requiring the caller to wait for the response (so the update call may complete before a response is delivered), at the protocol level this is not a one-way canister call (because the protocol does not support anything of the sort). So the canister itself will still have an open call context waiting for the response (which, among other things, means that the canister cannot be stopped before the response is received).

1 Like

Oh I did not know about the hidden open call context. Thanks for clarifying!