moxzi
Docs / Actor platforms / Actor platforms overview

Actor platforms overviewalpha

Run Motoko actors inside Dapr, Restate, Orleans, Akka, Proto.Actor, Cloudflare, Temporal, Ray or wasmCloud.

A compiled Motoko actor can run inside an actor platform you already operate. The platform decides where each actor runs, delivers its messages one at a time, and stores its state. moxzi runs the actor's code inside the platform's process, with the same rules as on the Internet Computer: a trap rolls back the message, await waits for another actor's reply, and upgrades keep state.

Start a project#

moxzi host new PLATFORM DIR writes a working project: a Motoko actor, moxzi's adapter for the platform, and a run.sh that builds both, starts what the platform needs, and calls the actor.

moxzi host new wasmcloud hello
host new: wasmcloud project (counter example) in ./hello — cd there and ./run.sh
cd hello
ONCE=1 ./run.sh
actor.mo -> actor.wasm + actor.did (242743 bytes, 1 file(s), 50 steps, 0.50s)
Counter/1.inc() -> [1]

Run it again, and the same actor answers 2: a new host process got the state back from the platform's store.

ONCE=1 ./run.sh
actor.mo -> actor.wasm + actor.did (242743 bytes, 1 file(s), 50 steps, 0.50s)
Counter/1.inc() -> [2]

Without ONCE=1, run.sh keeps the host running so you can call it:

curl -X POST localhost:8090/actors/Counter/1/method/inc \
  -H 'content-type: application/json' -d '[]'

Platforms#

Platformhost new nameYou needActor state is stored in
wasmCloudwasmcloudNothing elseA wasi:keyvalue bucket on disk
Proto.ActorprotoactorGo, DockerPostgres
DaprdaprGo, the Dapr CLI after dapr initDapr's state store
RestaterestateDockerRestate's state
TemporaltemporalGo, the Temporal CLI, DockerPostgres
Cloudflare Durable ObjectscloudflareNode.jsDurable Object storage
Orleansorleans.NET 8 SDK, DockerPostgres
Akka (Apache Pekko)akkaA JDK, coursier (cs), DockerPostgres
RayrayPython 3 with the project's host/requirements.txt, DockerPostgres

moxzi host new needs the release's SDK and hosts bundles, unpacked into the same directory as moxzi:

tar -xzf moxzi-0.1.0-alpha.7-aarch64-apple-darwin.tar.gz
tar -xzf moxzi-sdk-0.1.0-alpha.7-aarch64-apple-darwin.tar.gz
tar -xzf moxzi-hosts-0.1.0-alpha.7-aarch64-apple-darwin.tar.gz

Download them from https://moxzi.ai/releases/v0.1.0-alpha.7/. The install script installs only the compiler and server.

Examples#

--example NAME writes a project that shows more than a counter. moxzi host examples lists them.

ledger#

Accounts that deposit, withdraw and transfer:

moxzi host new wasmcloud shop --example ledger
cd shop
ONCE=1 ./run.sh
host new: wasmcloud project (ledger example) in ./shop — cd there and ./run.sh
account.mo -> account.wasm + account.did (259677 bytes, 1 file(s), 58 steps, 0.53s)
Account/alice.deposit(100), invocation dep-1 -> [100]
(the host process was killed and started again)
retry dep-1 after a host restart            -> [100]
Account/alice.withdraw(500), an overdraft   -> trapped
Account/alice.balance() after the trap      -> [100]
Account/alice.transfer("Account/bob", 30) -> [70]
Account/bob.balance()                       -> [30]

A deposit retried with the same invocation id (the x-moxzi-invocation-id header) is applied once, even after the host restarts. The overdraft traps, and the whole message is rolled back. The transfer awaits the other account's reply.

saga#

A trip that books a hotel and a flight, and releases the hotel if the flight is full:

moxzi host new wasmcloud trip --example saga
cd trip
ONCE=1 ./run.sh
host new: wasmcloud project (saga example) in ./trip — cd there and ./run.sh
trip.mo -> trip.wasm + trip.did (266077 bytes, 1 file(s), 58 steps, 0.52s)
hotel.mo -> hotel.wasm + hotel.did (243946 bytes, 1 file(s), 51 steps, 0.49s)
flight.mo -> flight.wasm + flight.did (243946 bytes, 1 file(s), 51 steps, 0.48s)
Trip/t1.book(h1, f1), h1 held                -> parked on call moxzi-call-v1.eyJuYW1lc3BhY2UiOiJ0cmlwIiwiZGVwbG95bWVudCI6ImRldiIsImFjdG9yX3R5cGUiOiJUcmlwIiwiYWN0b3Jfa2V5IjoidDEifQ.60954ddb3c8ea7be3946a85453dcf8ec.0000000000000001.await
(the host process was killed and started again)
Trip/t1.state() after a host restart         -> ["booking"]
deliver the held call to Hotel/h1            -> ["booked"]
Trip/t2.book(h2, f1): the flight is full     -> ["no seat (hotel released)"]
Hotel/h2.rooms() after the compensation      -> [2]

The booking waits on the hotel's reply while the host process is killed and restarted, then finishes when the reply arrives.

Calling an actor#

Each actor has a key, Type/id, such as Counter/1 or Account/alice. The platform creates the actor the first time its key is called.

RequestEffect
POST /actors/TYPE/ID/method/METHOD with a JSON array bodyCall a method. The reply is a JSON array of results
Header x-moxzi-invocation-id: IDMake a retry safe: a call with an id that already ran returns the recorded result

An actor finds another actor by key through the host's management canister:

transient let host : actor { moxzi_actor_of : ({ key : Text }) -> async Principal } = actor "aaaaa-aa";

public func payBob(amount : Nat) : async Nat {
  let bob : actor { credit : (Nat) -> async Nat } =
    actor (debug_show (await host.moxzi_actor_of({ key = "Account/bob" })));
  await bob.credit(amount)
};

moxzi_actor_of exists only on actor platforms, not on the Internet Computer.

Next steps#

On this pageStart a projectPlatformsExamplesledgersagaCalling an actorNext steps