runa/docs/runtime.md

73 lines
3.2 KiB
Markdown

# Phase 1 actor prototype
Run the feasibility probes and two-actor demonstration with:
```sh
cargo run -p runa
mise run pre-commit
```
The executable loads [counter.rn](../runa-std/actors/counter.rn), spawns two
actors sharing one implementation, and sends a structured message. The sender
commits state 1 and sends a message that moves the receiver from state 10 to 15.
## Current contracts
- `runa-actor` owns actor, mailbox and implementation IDs, structured messages,
snapshots, statuses and lifecycle events.
- `runa-rune` owns compilation and typed bounded invocation execution.
- `runa-runtime` owns implementation registration, queues, private committed
state, scheduling, message effects and lifecycle coordination.
- `runa` composes the experiment and demonstration.
An implementation is published once under an ID. Actors reference that exact
implementation. IDs and incarnation counters use checked increments.
Prototype state is an `i64`; messages contain integer `kind` and `value`
fields. Rune handlers have this deliberately restricted interface:
```text
handle(state, kind, value) -> (new_state, [(target_actor_id, kind, value), ...])
```
The returned effect vector describes sends; handlers cannot access the runtime
or directly mutate committed state. General schema/versioned values and
capability-bearing contexts are future work.
## Scheduling and lifecycle
`tick(nonzero_budget)` gives each runnable actor one bounded slice in ID order.
FIFO queues are bounded, including the reserved message in capacity accounting.
A queued message is reserved when its invocation starts. Subsequent messages
stay queued, including while the actor awaits. A wake marks an awaiting actor
runnable; the caller still needs to drive ticks.
Successful handlers validate every send target and its aggregate queue
capacity before updating state, acknowledging the reserved message, and
enqueueing effects. Invalid effects fail the actor without partial sends or a
state commit. This all-or-nothing behavior is in-memory only, not a durable
transaction.
Runtime errors retain the last committed state and reserved message, set an
observable failed status, and emit a failure event. External sends return errors
for unknown, unavailable, or full actors.
Stopping drops the invocation, retaining committed state, mailbox and reserved
message. Restarting a stopped or failed actor preserves IDs, increments its
incarnation, and puts its reserved message at the front of the queue. Restart
is explicit; there is no automatic poison-message retry or supervision policy.
## Limits
This is not yet a full image: no persistent mailboxes, transactional outbox,
supervisors, hot upgrades, API server, GUI, or automatic image bootstrap.
The example default script is bundled through `include_str!`.
Messages are not accepted by stopped/failed actors.
Native functions must be nonblocking. Dropping a future proves cleanup only
for the controlled test operation, not rollback of arbitrary external effects.
Instruction slices cannot interrupt a native callback.
The [execution decision](decisions/0001-worker-local-execution.md) records the
scheduling trade-offs. Heap profiling and source-level debugging remain open.