Skip to main content

machine

from lium.sdk import machine

Defined in lium.sdk.decorators.

def machine(
machine: str,
template_id: Optional[str] = None,
cleanup: bool = True,
requirements: Optional[Sequence[str]] = None,
*,
timeout: Optional[float] = 3600,
keep_warm: float = 0,
local: bool = False,
quiet: bool = False
):

Decorator to execute a function on a remote Lium machine.

Creates a new pod, sends function source code and executes it remotely, returns the result, and optionally cleans up the pod.

The decorated function also offers f.remote(*a) (same as f(*a)), f.local(*a) (run the original here), f.map(iterable) (run every item on one pod, rented once) and f.close() (remove the pod kept by keep_warm).

Arguments travel as a pickle: your own bytes, loaded on your own pod as they are. The result comes back from provider hardware, so nothing it contains is unpickled here: it travels as a JSON envelope plus an .npz sidecar for numpy arrays, read with allow_pickle=False. What round-trips, exactly: None, bool, int, float, str, bytes; list, tuple, set, frozenset and dict of those, nested; datetime/date/time/timedelta, Decimal, pathlib.Path, uuid.UUID; numpy.ndarray (any dtype without Python objects, any shape) and numpy scalars. Anything else — a dataclass, an Enum, an OrderedDict, a tensor, an ndarray subclass — raises ResultEncodingError on the pod, naming the type and its place in the result, and is re-raised here (return .tolist(), dict(x), x.value instead). Only the function's own def is sent: import what it needs inside the body and pass everything else as arguments. Whatever the function prints is relayed to this process's stdout/stderr while it runs. An exception raised on the pod is re-raised here with the same type when that type is a builtin (except ValueError works; its args come along when they are plain data, else its message); other types come back as RemoteExecutionError. Either way the __cause__ is a RemoteExecutionError carrying the remote traceback, exit code and captured output.

Arguments:

  • machine: "<count>x<gpu>" or "<gpu>" — e.g. "1xH200", "RTX4090", "2xA100". The count defaults to 1. The GPU is named as lium ls --gpu takes it (H100, RTX4090, rtx pro 6000, a bare 4090) and has to match the node's type whole — "A100" never rents an RTX A1000. The cheapest node with exactly that many GPUs of that type free to rent is rented (a split host with 2 of 8 free is a 2xA100) and billed for those — by the backend in one call (rent()) when it offers rent_by_spec, else picked here from a listing; when none matches, the error names the types the listing has.
  • template_id: Docker template ID (optional, uses the node's default if not specified)
  • cleanup: Whether to delete the pod after execution (default: True)
  • requirements: Optional iterable of pip-installable packages to install on the pod. They go into a venv that also sees the image's own packages, created and populated once per pod and reused by later calls with the same list.
  • timeout: Seconds the function may run on the pod before it is killed (default 1 h; None for no limit; 0 or a negative number is refused when decorating). A fraction of a second is rounded up to the next second for the kill. The pod is also scheduled for removal at timeout + 15 min (24 h when timeout=None) so a caller that dies mid-call cannot leave it billing.
  • keep_warm: Seconds the pod stays after a call for the next one — from this process or the next run of the script (the pod is found by name). Default 0: the pod is removed when the call returns. The pod is scheduled for removal server-side keep_warm + 2 min after each call, so nothing depends on the caller coming back.
  • local: Run the function in this process instead (LIUM_MACHINE_LOCAL=1 does the same for every decorated function) — for tests and offline work.
  • quiet: Suppress the one-line progress messages written to stderr.