Job platform.job@1

Generated at from openvibe-contracts v0.86.0 and openvibe-sdk v0.26.0.

Version
1.0.0
Owner
network
Visibility
public
Status
active
Compatibility
backward
Decision
ADR-034
Schema
https://openvibe.network/contracts/platform/job.v1.json

platform.job@1: one unit of work a dispatcher (OpenVibe.Bot now, Fabric later) hands to an execution worker (plan T14 Run; ADR-034 proposed). It rides the device control link inside a `job` frame (platform.job-frame@1). The worker answers it with `ack` (accepted) or `nack` (refused: an unknown or unimplemented class, a missing artifact, limits it cannot honor, the local kill switch), then runs it at most once. Metering: a running `function` job is billed by wall-clock second as platform.usage-sample@1 readings; platform.job-frame@1 `job_usage` gives the mapping.

Fields

FieldTypeRequiredDescriptionConstraints
idstringyesMinted by the dispatcher (job_<ULID>): the idempotency and ack key, as a Node command `id` is. A worker that already holds or ran this id never runs it again: a resent `job` is acked again while it runs and answered with its `job_exit` once it ended. Never reused: it is the stem of every usage reading's key (`run:<id>:<second>`).
  • pattern ^job_[0-9A-HJKMNP-TV-Z]{26}$
classplatform.runtime-classyes
artifactobjectThe pre-registered artifact to run; required for class `function`.
  • no other fields
artifact.namestringyes
  • pattern ^[a-z0-9][a-z0-9._-]{0,127}$
artifact.versionstringyesOne exact version, never a range
  • pattern ^[0-9A-Za-z][0-9A-Za-z.+-]{0,63}$
argsobjectyesThe artifact's declared input as JSON; the whole `job` frame stays within the link's 1 MiB frame limit.
ttl_msintegeryesLifetime from the worker's receipt of the job, covering any wait and the run; the worker caps it with its own local maximum (the stricter wins, as with `max_command_ms`). When it runs out, a job not yet started never starts and a running one is killed; either way `job_exit` says `ttl`.
  • minimum 1
limitsobjectyesCaps the worker enforces on the running process (merged stricter with its local caps); exceeding one kills the job and `job_exit` says `limit`.
  • no other fields
limits.wall_msintegeryesRunning time from `job_started`
  • minimum 1
limits.cpu_msintegeryesCPU time, user plus system
  • minimum 1
limits.mem_bytesintegeryesPeak resident memory
  • minimum 1
netenumNetwork policy; absent means `deny` (no network at all). Further policies are added to v1 additively, and a worker refuses (`nack`) a policy it does not know.
  • one of "deny"
  • default "deny"

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: function
{
  "id": "job_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "function",
  "artifact": {
    "name": "thumbnail",
    "version": "1.2.0"
  },
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000,
    "mem_bytes": 268435456
  },
  "net": "deny"
}
Valid: net-absent-means-deny
{
  "id": "job_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "function",
  "artifact": {
    "name": "thumbnail",
    "version": "1.2.0"
  },
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000,
    "mem_bytes": 268435456
  }
}
Valid: reserved-class-without-artifact
{
  "id": "job_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "gpu",
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000,
    "mem_bytes": 268435456
  },
  "net": "deny"
}
Rejected: artifact-version-range
{
  "id": "job_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "function",
  "artifact": {
    "name": "thumbnail",
    "version": "^1.2"
  },
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000,
    "mem_bytes": 268435456
  },
  "net": "deny"
}
Rejected: function-without-artifact
{
  "id": "job_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "function",
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000,
    "mem_bytes": 268435456
  },
  "net": "deny"
}
Rejected: id-without-prefix
{
  "id": "01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "function",
  "artifact": {
    "name": "thumbnail",
    "version": "1.2.0"
  },
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000,
    "mem_bytes": 268435456
  },
  "net": "deny"
}
Rejected: limits-without-mem
{
  "id": "job_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "function",
  "artifact": {
    "name": "thumbnail",
    "version": "1.2.0"
  },
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000
  },
  "net": "deny"
}
Rejected: net-allow
{
  "id": "job_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "class": "function",
  "artifact": {
    "name": "thumbnail",
    "version": "1.2.0"
  },
  "args": {
    "width": 320
  },
  "ttl_ms": 60000,
  "limits": {
    "wall_ms": 30000,
    "cpu_ms": 30000,
    "mem_bytes": 268435456
  },
  "net": "allow"
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('platform.job@1', value);   // { valid, errors: [{ path, message }] }