runa/docs/decisions/0001-worker-local-execution.md

52 lines
2.3 KiB
Markdown

# 0001: Worker-local execution with instruction slices
Status: Accepted for the Phase 1 prototype
## Decision
Share immutable Rune 0.14.2 compiled units and native contexts, but create an
independent VM stack for each invocation. Keep invocations and Rune values on
one worker. No actor-specific state lives in a shared context or native closure.
Use `VmExecution::async_step` inside an owned, pinned invocation future.
Preserve that future across awaits; cancelling an individual `async_step`
future and creating another could lose the pending await.
Yield to the host after each completed step. `Invocation::poll_slice` executes
at most its configured number of step polls and returns one of:
- `Completed`: the converted result is ready.
- `Awaiting`: a native async operation is pending.
- `BudgetExhausted`: the host slice is consumed; the invocation is resumable.
- `Failed`: execution or result conversion failed.
This boundary does not inspect Rune error text. The older Phase 0 budget probe
still checks the pinned budget diagnostic as a compatibility experiment.
The single-worker runtime visits each runnable actor once per tick. Each actor
has at most one reserved message and one invocation. Awaiting actors are
repolled after a wake, not continually busy-polled.
## Alternatives
Rune's aggregate instruction budget is cheaper than one-step scheduling but
its typed exhaustion discriminator is private in 0.14.2. Parsing its display
text is not suitable for runtime policy. An upstream typed slicing API could
replace stepping later, after measurement.
Moving active executions between workers adds thread-safety obligations not
needed by this prototype. No execution-adapter trait or shared core crate is
introduced without a concrete consumer.
## Consequences
This is bounded cooperative VM scheduling, not wall-clock preemption.
One Rune instruction can call native code; blocking callbacks or expensive
native operations can still monopolize a worker. Native callbacks must be
reviewed for nonblocking behavior and cancellation.
Tests establish fairness for pure Rune runaway loops, budgets before and after
awaiting, wake-driven resumption, and local-future cleanup on cancellation.
They do not establish safe interruption of arbitrary external I/O, heap limits,
source debugging, or fairness across real worker threads.