Skip to content

Guides

Background commands

Start long-running commands that outlive the request, page through their logs, and kill them.

On this page

A background command runs detached: the request returns as soon as it starts, there is no timeout, and its combined output goes to a log you can page through. Use it for servers, watchers, and jobs longer than the 10-minute exec limit. Each start is also recorded in the machine's command history.

Start one

const command = await machine.commands.start("npm run dev");
console.log(command.command_id);

The body takes exactly one of argv or command (a /bin/sh -c string of at most 8 KiB). The answer is 202 with a command_id, which is also the ID of the operation that starts it, and a command_url. The CLI has no background-command subcommand yet; the console's Terminal tab can start and watch them.

Status and logs

let offset = 0;
const status = await machine.commands.status(command.command_id, { logOffset: offset });
if (status.log) {
  process.stdout.write(Buffer.from(status.log.data_base64, "base64"));
  offset = status.log.next_offset;
}

GET /v1/machines/{id}/commands/{command_id} returns the status and a window of the log starting at log_offset (default 0), at most log_limit bytes (1 to 1,048,576; default 65,536). Pass the returned next_offset as the next log_offset. If the read is still queued, the answer is 202 with an operation to follow; the SDKs do that for you.

statusMeaning
startingBeing started.
failed_to_startIt could not start; see error_code.
runningRunning.
exitedFinished; exit_code holds its status.
killedKilled; signal holds the signal when known.
unknownThe machine has no record of it, for example after a reboot. Stop polling.

VMYard asks for the status before reading the log, so once a command reports exited, its log is complete. Logs are bytes: decode them as a stream so a character split across two pages stays whole.

machine.commands.wait(id) in the SDKs polls until the command is exited, killed, or failed_to_start.

Kill one

await machine.commands.kill(command.command_id);

Killing is an operation. Read the status afterwards: a command is only killed once it reports so.

Limits

Background commands, like everything inside a machine, need a running machine and Owner, Admin, or Operator access (or a use_existing key). Reading the status of a command reaches into the machine, so even reads need use_existing; a read_only key gets 403 insufficient_scope.