marla.runtime
Local vs. distributed execution, device resolution, and the SPADE-independent lifecycle/failure logic.
Local execution mode (spec section 4.1).
All configured agents run in one Python process, started from one
spade.run() main function, sharing one asyncio event loop – but they
still communicate exclusively through real SPADE messages over a real (here,
embedded) XMPP server, never through direct Python method calls between
agents.
- exception marla.runtime.local.LocalRunError[source]
Bases:
ExceptionRaised when a local-mode run ends in failure (mirrors EXPERIMENT_FAILED).
- marla.runtime.local.resolve_debug_dir(config, run_id)[source]
Where
--debugwrites every Plan Maker query/response pair (see PlanMakerAgent).Deliberately its own top-level
debug/directory, not nested undermetrics.output_directory(runs/by default) – it holds ad hoc inspection files for a human, not run metrics/results, and is easy to overlook several directories deep.
- marla.runtime.local.resolve_run_dir(config)[source]
<metrics.output_directory>/<experiment-name>/<run-id>/(spec section 21).
- marla.runtime.local.run_local(config, config_dir, num_rollouts, embedded_xmpp_server=True, debug=False)[source]
Run a local-mode experiment; blocks until the RL Orchestrator finishes.
Raises
LocalRunErrorif the run ended in failure. Returns the stoppedRLOrchestratorAgent(holdingtraining_result) on success.SPADE’s
Containeris a process-wide singleton, and its event loop is closed at the end ofspade.run()– callingrun_localmore than once in the same process reuses a closed loop and fails. This matches real usage (marla runis always a fresh process); tests that need more than one local-mode run must isolate each in its own subprocess.
Distributed execution mode (spec section 4.2).
Each marla run process starts only the agents named via repeatable
--agent options (by alias or JID), connecting to the configured,
externally-reachable XMPP server – distributed mode never uses the
embedded pyjabber server, that is a local-mode convenience only. Every
process loads the identical configuration and shares experiment.run_id
(already enforced by config validation); only the process that starts
rl_orchestrator owns NASimEmu and writes central metrics.
- exception marla.runtime.distributed.DistributedRunError[source]
Bases:
ExceptionRaised when a distributed-mode process ends in failure.
- marla.runtime.distributed.run_distributed(config, config_dir, selected_aliases, num_rollouts, debug=False)[source]
Entry point for
marla runin distributed mode.Starts only the agents in
selected_aliasesand connects to the configured (real, externally reachable) XMPP server. Blocks until every locally-started agent finishes; raisesDistributedRunErrorif any of them ended in failure.Like
marla.runtime.local.run_local(), this can only be called once per process (SPADE’sContaineris a process-wide singleton) – which matches real usage, sincemarla runis always a fresh process.
Startup/shutdown/failure coordination logic (spec section 5), SPADE-free.
There is no Coordinator component; the RL Orchestrator coordinates startup
and shutdown directly. This module holds the pure decision logic –
“given these READY/failure events, are we ready to start, and if not, why
did we fail” – independent of SPADE/XMPP wiring, so it can be unit tested
with a plain asyncio.Queue instead of a real agent connection. The SPADE
glue that turns real messages and presence callbacks into the events this
module consumes lives in marla.agents.lifecycle_behaviours.
There is no elapsed-time response timeout (spec section 5/10): this module waits indefinitely on the event queue. Only an explicit failure/disconnect event ends the wait early.
- class marla.runtime.lifecycle.FailureSignal(alias, reason)[source]
Bases:
objectA participant failed, disconnected, or reported EXPERIMENT_FAILED.
- exception marla.runtime.lifecycle.LifecycleFailedError(alias, reason)[source]
Bases:
ExceptionRaised when a required participant fails or disconnects during startup.
- class marla.runtime.lifecycle.ReadySignal(alias, jid, schema_version, model_version, resolved_device)[source]
Bases:
objectA participant reported READY.
- marla.runtime.lifecycle.register_sigint_handler(stop_event)[source]
Arm a one-shot Ctrl+C handler that requests a graceful stop.
A synchronous, blocking Plan Maker consultation can’t safely be interrupted mid-computation (there is no clean cancellation point inside a torch forward pass), so the first SIGINT just sets
stop_event(checked between environment steps – seelearning.rollout.RolloutCollector.collect) and removes itself. A stopped run still finishes the in-flight step and then follows the same STOP_EXPERIMENT/agent.stop() shutdown path as a normal completion, rather than tearing down mid-message. A second Ctrl+C falls through to Python’s default KeyboardInterrupt handling, for an immediate, unconditional exit if the graceful stop doesn’t return promptly enough.- Parameters:
stop_event (Event)
- Return type:
None
- async marla.runtime.lifecycle.wait_for_all_ready(required_aliases, events)[source]
Block until every required alias has signaled READY.
Raises
LifecycleFailedErroron the first failure/disconnect event concerning a required alias. Events for aliases outsiderequired_aliasesare ignored (defensive; should not occur in practice). Returns immediately with an empty dict ifrequired_aliasesis empty (the baseline variant has no participants to wait for).- Parameters:
events (Queue[ReadySignal | FailureSignal])
- Return type:
Resolve the device: cpu | gpu | auto configuration option.
Each machine/process resolves its own device independently (this matters in distributed mode, where the Plan Maker may run on different hardware than the RL Orchestrator). Remote API model backends are never subject to these checks – only locally executed ML models are.
- exception marla.runtime.device.DeviceResolutionError[source]
Bases:
RuntimeErrorRaised when
device: gpuis requested but CUDA is unavailable/unusable.
- class marla.runtime.device.ResolvedDevice(requested, resolved)[source]
Bases:
objectRequested vs. actually-resolved device, recorded for reproducibility.
- marla.runtime.device.resolve_device(requested)[source]
Resolve
requestedinto a concrete device, per spec section 18.cpu: always resolves to CPU.gpu: must successfully initialize CUDA (availability check plus an actual tensor allocation), otherwise raisesDeviceResolutionErrorso startup fails before the agent reports ready.auto: CUDA if available, else CPU.
- Parameters:
requested (Literal['cpu', 'gpu', 'auto'])
- Return type: