Distributed PingPong
This tutorial runs the PingPong example across two terminals connected
via TCP. The ping object lives on node alpha and the pong object
lives on node beta. Calls cross the network transparently.
Prerequisites
Build the avm-node binary:
cd avm && cargo build -p avm-node
Running the demo
Open two terminals:
Terminal 1 — start the beta node (hosts pong):
just avm demo-beta
# or: RUST_LOG=info cargo run -p avm-node -- \
# --name beta --port 9002 --peer alpha:9001 --demo
Terminal 2 — start the alpha node (hosts ping, runs orchestrator):
just avm demo-alpha
# or: RUST_LOG=info cargo run -p avm-node -- \
# --name alpha --port 9001 --peer beta:9002 --demo --rounds 3
What happens
sequenceDiagram
participant A as alpha (ping)
participant N as Network (TCP)
participant B as beta (pong)
A->>A: create ping object
B->>B: create pong object
B->>N: CreateNotify(pong)
N->>A: CreateNotify(pong)
A->>A: orchestrator calls ping
A->>N: Call(pong, Ping msg)
N->>B: Call(pong, Ping msg)
B->>B: run pong behavior
B->>N: CallResponse(Pong msg)
N->>A: CallResponse(Pong msg)
A->>A: ping behavior resumes
A->>N: Call(pong, Ping msg)
Note over A,B: ...repeats until max rounds...
A->>A: ping returns "done"
- Beta creates the
pongobject locally and broadcasts aCreateNotifymessage to all peers. - Alpha receives the notification and updates its location directory:
pong → beta. - Alpha creates
pinglocally and runs the orchestrator program. - When
pingcallspong,execute_callsees thatponglives onbeta(different machine) and routes through theTcpTransport. - The call is serialized as JSON, sent over TCP, executed on beta, and the response returns the same way.
- When
pongcallspingback, the same process happens in reverse.
Wire protocol
Messages are length-prefixed JSON over TCP:
[4-byte big-endian length][UTF-8 JSON payload]
Message types:
| Message | Direction | Purpose |
|---|---|---|
Call | requester → owner | Synchronous object invocation |
CallResponse | owner → requester | Return value or error |
CreateNotify | creator → all | Update location directories |
DestroyNotify | destroyer → all | Remove from directories |
Ping/Pong | either | Keepalive |
Key concepts
- Location directory: each node maintains a map from
ObjectIdtoMachineId. Updated byCreateNotifybroadcasts. - Transport trait: the
TcpTransportimplementsavm_core::Transport, bridging the sync interpreter to the async TCP layer via oneshot channels. - Node-prefixed IDs:
FreshIdGen::with_prefix(u16)ensures globally uniqueObjectIds across nodes (top 16 bits = node identity). - Behaviors are local: each node registers its own behaviors. Only messages (values) cross the network, not code.