moxzi
Docs / Actor platforms / In process: the platform owns the image

In process: the platform owns the imagealpha

How does a Motoko actor run inside my platform's own process, and what does it cost?

In-process hosting runs a Motoko actor inside the platform's own process through moxzi-rts, a library, while the platform keeps the actor's durable image in its own store. It is the alpha-7 shape on all nine platforms. The separate moxzi-actor-host service each host page describes first still works; this is the faster form, and the one the numbers below measure.

Who owns what#

ConcernOwner
One turn at a time per key, placement, routingthe platform, as for its own actors
The actor's image (4 KiB pages, up to 32 dedup slots, a small metadata record)the platform's store: Postgres, Dapr's state store, Restate state, a keyvalue bucket, Durable Object storage
Executing Motoko, rollback on a trap, parked awaits, upgradesmoxzi-rts, in the platform's process
Durable timersthe platform's own (reminders, alarms, delayed sends)

Nothing is written to disk by moxzi. After a committing turn the runtime hands back a delta — the changed pages and the new metadata — and the platform commits it atomically, only if its stored image version is the one the delta extends. If it cannot commit, it evicts the actor; the next turn reactivates it from what the store holds.

The contract, as a function call#

moxzi-rts answers the actor-host contract version 3 (docs/host-abi.md in the repository) without HTTP. Its C interface is moxzi/rts/include/moxzi_rts.h:

int  moxzi_rts_new(ns, ns_len, dep, dep_len, &rts);
int  moxzi_rts_add_type(rts, name, name_len, wasm, wasm_len);
int  moxzi_rts_learn(rts, key, key_len);
int  moxzi_rts_call(rts, method, method_len, url, url_len, body, body_len, &status, &out, &out_len);
void moxzi_rts_free_buf(out, out_len);

moxzi_rts_call("POST", "/v3/begin", body) returns what POST /v3/begin returns over HTTP. Every adapter drives a turn the same way:

StepWhat the platform does
1send the turn with expectVersion, the image version its store holds
2on 409 {notActive}, send the same turn again with activate: {image} from the store
3on 409 {needModule: <hash>}, read the module stored under that hash and send the turn once more with activate: {image, module}
4commit the returned delta only if the stored version is delta.baseVersion; if that fails, call /v3/evict and fail the turn

The runtime usually has the module already — it hosts the type, or saw it earlier — so step 3 is rare, and a 380 KB module is neither read from the store nor sent on an ordinary activation. Store meta exactly as it arrives: meta.patches carries byte-level patches for pages whose stored copy is out of date, and only the runtime reads it. Store a delta's dedup chunks the way you store pages (overwrite by index) and return them as the image's dedup: they are the record that answers a retried turn exactly once, and an activation without them is refused.

Bindings#

PlatformBindingBuild the in-process host (from the named directory)
RestateRust, linkedmoxzi/: cargo build --release -p moxzi-restate --bin moxzi-restate-host
Temporalcgo, turns as local activitiesmoxzi/adapters/temporal/: go build -tags inproc -o moxzi-temporal-host .
Daprcgo, inside the Dapr appmoxzi/adapters/dapr/host/: go build -tags inproc -o moxzi-daprhost .
Proto.Actorcgo, in the cluster membermoxzi/adapters/protoactor/: go build -tags inproc -o moxzi-protoactor .
OrleansP/Invoke, in the silomoxzi/adapters/orleans/: dotnet publish -c Release -o out/orleans
Akka (Pekko)JNA, in the entitymoxzi/adapters/pekko/: bash build.sh <out>
Rayctypes, inside each key's Ray actormoxzi/adapters/ray/: nothing to build; set MOXZI_RTS_LIB to the library
wasmClouda wash-runtime host with a moxzi pluginmoxzi/adapters/wasmcloud/: cargo build --workspace --target wasm32-wasip2 --release --features in_process && (cd host && cargo build --release)
Cloudflarethe contract engine inside each Durable Objectmoxzi/adapters/cloudflare/: bash build-native.sh <modules-dir>

The cgo, P/Invoke, JNA and ctypes bindings load libmoxzi_rts from moxzi/target/release: build it first with cargo build --release -p moxzi-rts in moxzi/. Those hosts and Restate select the in-process form with MOXZI_IN_PROCESS=1; wasmCloud's and Cloudflare's in-process hosts are separate builds. The launch files the conformance harness uses, moxzi/conformance/hosts/<platform>-inproc.json, hold the exact commands and environment.

From a release, without Rust#

Each release carries the runtime prebuilt, in bundles that unpack into the same directory as the toolchain tarball (moxzi-<version>-<target>/):

BundleContents
moxzi-sdk-<version>-<target>.tar.gzlib/libmoxzi_rts.so (Linux) or lib/libmoxzi_rts.dylib (macOS), include/moxzi_rts.h, examples/rts_hello.c, and the adapter sources moxzi host new copies
moxzi-hosts-<version>-<target>.tar.gzthe prebuilt Restate, wasmCloud and Cloudflare hosts
moxzi-rts-static-<version>-<target>.tar.xzlib/libmoxzi_rts.a, for linking statically (large: it is all of wasmtime). Published in parts; join them with cat moxzi-rts-static-<version>-<target>.tar.xz.part-* > moxzi-rts-static-<version>-<target>.tar.xz, then check it against SHA256SUMS
tar -xzf moxzi-<version>-<target>.tar.gz        # the toolchain
tar -xzf moxzi-sdk-<version>-<target>.tar.gz    # + runtime and adapters
tar -xzf moxzi-hosts-<version>-<target>.tar.gz  # + prebuilt hosts (Restate, wasmCloud, Cloudflare)

The release is refused unless the example compiles against the staged library and runs an actor, so it is known to work:

cc examples/rts_hello.c -I include -L lib -lmoxzi_rts -Wl,-rpath,lib -o rts_hello
./moxzi build hello.mo -o hello.wasm
./rts_hello hello.wasm
# status 200; the answer is … bytes of JSON, most of it the delta to commit
# "response":{"candid":"…","result":["Hello, world!"],"status":"replied"},…
BindingUsing the release's library
C, or any language with a C FFIlink lib/ as above
Orleans, Pekkoset MOXZI_RTS_LIB_DIR to the tarball's lib/
Rayset MOXZI_RTS_LIB to lib/libmoxzi_rts.so (or .dylib)
Go (cgo), Rustbuild from the repository today (cargo build --release -p moxzi-rts); linking them against the tarball is not yet tested

What it costs#

Measured on the conformance fixture customer.mo, in process (docs/actor-cost-report.md):

CostValue
Resident memory per active actor~105 KiB (Linux), ~112 KiB (macOS)
Actors in one process100,000 in 13.9 GB
Activation from a stored image, to first reply~0.4 ms
Bytes a small turn stores~1.4 KB, averaged over 2,000 turns
Update latency against the platform's own durable actor1.4–1.7x on Linux (Proto.Actor)

scripts/actor_cost_ratchet.sh holds these on the release board.

Checking a host#

ToolWhat it proves
HOST=<platform>-inproc scripts/host_matrix_gate.shall 16 conformance scenarios against the real platform
MOXZI_BASELINE_VERIFY=1every image is checked against a full scan, and every rollback against live memory; the matrix gate sets it by default
scripts/host_latency_ratchet.shupdate latency as a ratio to the platform's own actor, per platform

Things you cannot do#

Next#

On this pageWho owns whatThe contract, as a function callBindingsFrom a release, without RustWhat it costsChecking a hostThings you cannot doNext