plesty.server.model.job

Long-running work on the bench as jobs: a record and a log.

An install, an update, a field test or an arbitrary command in a device’s environment takes seconds to minutes — too long for one request/reply and too interesting to run blind. A Job is the record of such a run: its command, pid, timestamps and exit code live in <home>/jobs/<id>.json and its stdout+stderr in <home>/logs/jobs/<id>.log. JobStore owns both files — creating, updating, listing records and reading logs by byte offset — so a job started by the agent is visible to the CLI and the GUI.

Starting and killing the process is not the model’s business: whoever launches it calls JobStore.create() before and JobStore.finish() after, and JobStore.refresh() settles a still-running record from the two facts only the process layer knows — is the pid alive, and what exit code was left.

Attributes

LOG_CHUNK

LOST_EXIT

CANCELLED_EXIT

Exceptions

JobError

A job record does not exist or cannot be read.

Classes

Job

One unit of long-running work.

JobStore

Job records and logs under a Home.

Functions

tail_file(→ str)

The last lines lines of path, read from the end in block steps.

_now(→ str)

Module Contents

plesty.server.model.job.LOG_CHUNK = 65536
plesty.server.model.job.LOST_EXIT = -1
plesty.server.model.job.CANCELLED_EXIT = -9
exception plesty.server.model.job.JobError

Bases: RuntimeError

A job record does not exist or cannot be read.

Initialize self. See help(type(self)) for accurate signature.

class plesty.server.model.job.Job

One unit of long-running work.

Variables:
  • id<name>-<kind>-<timestamp>, unique per bench.

  • name – Device instance the job belongs to.

  • kindinstall, update, field-test, command

  • command – The command line.

  • cwd – Working directory.

  • pid – Process id while it runs.

  • started_utc – ISO timestamp of the launch.

  • finished_utc – ISO timestamp of the end, or None while running.

  • returncode – Exit code once finished (None while running; LOST_EXIT when the process vanished without one).

  • log – Path of the log file.

  • detail – Kind-specific data (e.g. the reports a field test wrote).

id: str
name: str
kind: str
command: list[str]
cwd: str
pid: int | None
started_utc: str
finished_utc: str | None = None
returncode: int | None = None
log: str = ''
detail: dict[str, Any]
property running: bool

Whether the job has not finished yet.

Return type:

bool

property state: str

running, done (exit 0), failed (any other exit).

Return type:

str

to_dict() dict[str, Any]

JSON form, with the derived state included.

Return type:

dict[str, Any]

classmethod from_dict(data: collections.abc.Mapping[str, Any]) Job

Rebuild a record from to_dict() output (extra keys ignored).

Parameters:

data (collections.abc.Mapping[str, Any])

Return type:

Job

class plesty.server.model.job.JobStore(home: plesty.server.model.home.Home)

Job records and logs under a Home.

Bind to a home.

Parameters:

home (plesty.server.model.home.Home) – The bench home.

home
create(name: str, kind: str, command: list[str], cwd: str | os.PathLike[str], pid: int | None = None, detail: collections.abc.Mapping[str, Any] | None = None) Job

Open a new record and return it (state running).

Parameters:
  • name (str) – Device instance the job belongs to.

  • kind (str) – Job kind, part of the id.

  • command (list[str]) – The command line.

  • cwd (str | os.PathLike[str]) – Working directory.

  • pid (int | None) – Process id when already known.

  • detail (collections.abc.Mapping[str, Any] | None) – Kind-specific data stored on the record.

Return type:

Job

save(job: Job) pathlib.Path

Write job to its record file; returns the path.

Parameters:

job (Job)

Return type:

pathlib.Path

get(job_id: str) Job | None

The record of job_id, or None when unknown or unreadable.

Parameters:

job_id (str)

Return type:

Job | None

require(job_id: str) Job

Like get() but raises JobError when unknown.

Parameters:

job_id (str)

Return type:

Job

list(name: str | None = None, kind: str | None = None) list[Job]

Jobs on record, newest first, optionally filtered by device and kind.

Parameters:
  • name (str | None)

  • kind (str | None)

Return type:

list[Job]

finish(job_id: str, returncode: int) Job

Close the record of job_id with returncode; returns it.

Parameters:
  • job_id (str)

  • returncode (int)

Return type:

Job

refresh(job: Job, alive: collections.abc.Callable[[int], bool], exit_code: collections.abc.Callable[[str], int | None]) Job

Settle a running record against what the process layer knows.

Parameters:
  • job (Job) – The record to bring up to date (mutated and saved when it ends).

  • alive (collections.abc.Callable[[int], bool]) – Whether a pid is still running.

  • exit_code (collections.abc.Callable[[str], int | None]) – The exit code left for a job id, or None when none.

Returns:

job, finished when an exit code exists or the pid is gone (LOST_EXIT then), unchanged while it still runs.

Return type:

Job

log(job_id: str, offset: int = 0, limit: int = LOG_CHUNK) tuple[str, int]

Read the job log from byte offset.

Parameters:
  • job_id (str) – The job.

  • offset (int) – Where the previous read stopped (0 for the start).

  • limit (int) – Maximum bytes to return.

Returns:

The text read and the offset to continue from. Decoding is lenient — a chunk may cut a multi-byte character.

Return type:

tuple[str, int]

tail(job_id: str, lines: int = 50) str

The last lines lines of the job log (empty when there is none yet).

Parameters:
  • job_id (str)

  • lines (int)

Return type:

str

plesty.server.model.job.tail_file(path: pathlib.Path, lines: int, block: int = 8192) str

The last lines lines of path, read from the end in block steps.

Parameters:
  • path (pathlib.Path)

  • lines (int)

  • block (int)

Return type:

str

plesty.server.model.job._now() str
Return type:

str