Dista · API

dista.worker

A worker: runs tasks for the head and serves its results to peers.

A small result (up to INLINE_LIMIT bytes) goes back to the head, which forwards it. A larger one stays here: in a shared mapping in the node's store (see store.mojo), or in memory if the store is off. The worker tells the head where it is; a reader on this host maps the file, and one elsewhere fetches it from this worker's object server.

So a worker is an event loop over the head, its listener, the drivers and workers fetching from it, and the workers it fetches from. A task whose inputs live on other workers waits, parked, until they've all arrived; the worker keeps serving fetches meanwhile. No worker ever waits on another one synchronously, so two workers that need each other's results can't deadlock. Running a task does block the loop, so fetches from this worker wait until the current task finishes.

A result here lives until the head says free, once nothing references it. Inputs fetched from peers are copies, kept only until the tasks waiting on them have their arguments.

A worker the head gives an actor builds its state and then runs only that actor's calls, in the order they come. A kill destroys the state, and the worker goes back to running tasks. Between calls the head may ask for a checkpoint: the worker writes the state through the codec to DISTA_CHECKPOINT_URI (see checkpoint.mojo), and deletes the checkpoint before it. An actor restarted elsewhere is restored from the last one.

A worker told to stop (SIGTERM, as Kubernetes sends) drains: it tells the head, which sends it no more work and has other workers adopt the results it holds, each fetching its copy from here. It finishes what it was given, and once the head says stop, it serves fetches a moment longer, for tasks given its old locations, and exits. DISTA_DRAIN_SECONDS (default 25, inside Kubernetes' default grace period of 30) bounds the whole drain.

If the head goes away, run returns and the results here stay. rejoin introduces the worker to a new head and reports what it holds; the tasks it had queued are dropped, since their drivers resubmit them. An actor it hosted is destroyed: actors don't survive a head restart yet, though their checkpoints stay.

Structs

InputSpec

struct InputSpec

One input in a task-inputs frame: its bytes, or where to get them.

Implements Copyable, Movable

Fields
object_id: UInt64
inline: Bool
bytes: List[UInt8]
location: Optional[Location]

TaskInputs

struct TaskInputs

Implements Movable

Fields
many: Int: A TaskMany's number of results; 0 for any other task.
gather: Bool
inputs: List[InputSpec]
value: List[UInt8]: A TaskWith's value, which goes before the inputs; or empty.

Worker

struct Worker[dispatch: def(UInt64, List[UInt8], mut List[UInt8], mut TaskContext) raises thin -> None, create: def(UInt64, List[UInt8]) raises thin -> StatePtr, call: def(UInt64, UInt64, Pointer[NoneType, MutUntrackedOrigin], List[UInt8], mut List[UInt8], mut TaskContext) raises thin -> None, destroy: def(UInt64, Pointer[NoneType, MutUntrackedOrigin]) thin -> None, save: def(UInt64, Pointer[NoneType, MutUntrackedOrigin], mut List[UInt8]) raises thin -> None, restore: def(UInt64, List[UInt8]) raises thin -> StatePtr]

Implements Movable

Fields
stopped: Bool: The head said stop, or the worker drained: run returned for good.

__init__

def __init__(out self, var head: Stream, registry_hash: UInt64, head_addr: String = "", resume_at: String = "")

Starts the object server and says hello to the head on head.

head_addr is where a task's client connects, and resume_at where it reconnects after a head restart ("" in local mode).

__deinit__

def __deinit__(deinit self)

rejoin

def rejoin(mut self, var head: Stream, registry_hash: UInt64)

Says hello to a new head and reports the results held here.

run

def run(mut self)

Serves until the head hangs up, or until a drain ends.

Functions

parse_task_inputs

def parse_task_inputs(payload: Span[UInt8]) -> TaskInputs

A task-inputs payload, checked: a malformed one raises.

Aliases

comptime INLINE_LIMIT = 65536

Results up to this size travel through the head; larger ones stay put.

comptime LINGER_NS = UInt64(1000000000)

How long a drained worker keeps serving fetches after the head says stop: a task sent before its inputs moved may still fetch them from here.

comptime DispatchFn = def(UInt64, List[UInt8], mut List[UInt8], mut TaskContext) raises thin -> None

Runs task task_id on encoded arguments, appending the encoded result; a CtxTask gets the worker's TaskContext.

comptime CreateFn = def(UInt64, List[UInt8]) raises thin -> StatePtr

Builds actor type type_id's state from its encoded argument.

comptime CallFn = def(UInt64, UInt64, Pointer[NoneType, MutUntrackedOrigin], List[UInt8], mut List[UInt8], mut TaskContext) raises thin -> None

Runs method method_id on the state of an actor of type type_id.

comptime DestroyFn = def(UInt64, Pointer[NoneType, MutUntrackedOrigin]) thin -> None

Destroys the state of an actor of type type_id.

comptime SaveFn = def(UInt64, Pointer[NoneType, MutUntrackedOrigin], mut List[UInt8]) raises thin -> None

Appends the encoded state of an actor of type type_id.

comptime RestoreFn = def(UInt64, List[UInt8]) raises thin -> StatePtr

Builds actor type type_id's state from a checkpoint.