Skip to content

Cross-app calls

A run may send messages to other apps (env::xcall(app, method, &args)). The message is a follow-up: it runs after the sending entry commits. The guest API is in Cross-app calls; this page is how the cluster runs them (crates/node/src/component/xcall.rs).

A run’s messages go to its outcome. When the entry ends Ok, they are appended, in order, to the source app’s outbox, kept as host rows in the source app’s state. A failed run sends nothing.

The source’s leader delivers the head of its outbox one message at a time, so messages leave each source in order. The target runs the method as an xcall delivery, with Caller::App(<source>).

The node that runs the target checks:

  1. Entry point. The target method’s ABI must allow the source: #[app::allow(app = "<source>")] or allow(app = "*") (allowApps).
  2. Boundary. The two apps belong to the same organization, or, outside any organization, have the same owner.
  3. Provenance. The target sees the caller as Caller::App(<source>), set by the node; no argument can claim it.

Synchronous calls and views (env::xcall_call, env::xcall_view) pass the same checks and answer at once.

The target keeps, per source app, the highest sequence number it applied; a message at or below it is answered as delivered without running. A leader change on either side never runs a message twice.

A timeout or an unreachable target is retried with backoff for up to an hour from the send. Then, or at once for a deleted target, one outside the organization, or one that is not a component (an SDK 0.12 app the node no longer runs), the message goes to the source’s dead letters (the newest 1,000), and the source’s onXcallFailed runs if its ABI has one that allows the system. Anything the target answered, an app error or a trap included, is a final answer.

A run may send at most 100 messages; an empty or overlong app id or method, or a reserved (__) method, is refused at the send.