Skip to content

Job reports API

Job reports are part of Pro and Team. How to set one up: Get told when a job fails.

Request POST https://api.cloudviewer.app/v1/ingest/job
Authentication Header X-Agent-Token: <agent_token>, the per-server token of the monitored server the job belongs to
Content type application/json
Body At most 4 KiB

The token decides which server a job belongs to. A job that runs somewhere else uses the token of the server it relates to. On a server with the agent, the token is CV_AGENT_TOKEN in /etc/cloudviewer-agent/agent.env.

{
"reports": [
{ "job_name": "backup-s3", "exit_code": 0, "duration_seconds": 412, "max_age_seconds": 93600 }
]
}
Field Type Required Meaning
reports array of 1 to 16 objects yes One object per job
reports[].job_name string, ^[a-z0-9][a-z0-9-_.]{0,63}$ yes The job’s name on its server. The first report with a new name creates the job
reports[].exit_code integer, 32-bit yes 0 is a success, anything else a failure
reports[].duration_seconds number, 0 or more no How long the run took
reports[].max_age_seconds number, more than 0 no How old the last successful run may get before the job is stale. Leave it out for failure alerts only
  • job_name: lowercase letters, digits, -, _ and ., 1 to 64 characters, starting with a letter or a digit.
  • Unknown fields are refused. There is no message field and no time field: the time of the run is when Cloud Viewer receives the report.
  • A request is all or nothing: if one report is invalid, none is stored.
  • Each report replaces the job’s last state, including max_age_seconds. A report without it removes the job’s time limit.
  • Only a report with exit code 0 moves the time of the last success.
  • Cloud Viewer keeps the last state of each job, not a history of runs: last run, last success, last exit code, last duration and the time limit.
Status code When
202 Accepted. Body: {"accepted": <number of reports>}
401 unauthorized Token missing or unknown
401 agent_revoked Token revoked
403 entitlement_required The team’s plan has no job reports
413 validation_failed Body larger than 4 KiB
422 invalid_schema Not JSON, an unknown field, no exit_code, no or more than 16 reports, or a number out of range
422 invalid_job_name job_name does not match the pattern
422 job_limit_reached The report would create a 17th job on the server
429 rate_limited More than the request budget. Retry-After says when to retry
503 internal, busy Cloud Viewer is busy or unavailable. Retry after Retry-After

Errors are JSON: {"code": "…", "message": "…"}. The message names the field, for example reports[0].job_name must match [a-z0-9][a-z0-9-_.]{0,63}.

Limit Value
Body 4 KiB
Reports per request 1 to 16
Jobs per server 16. Reports for jobs that already exist are always accepted
Requests per token 2 a minute, bursts of up to 16

Many cron jobs that start on the hour fit into the burst, and one request can carry up to 16 jobs. A job stays as long as its server; there is no way yet to remove a single job.

Terminal window
cloudviewer-report --job <name> [--max-age <duration>] [--token-file <path>] -- <command> [arguments…]
Flag Meaning
--job <name> Required. The job_name
--max-age <duration> Seconds, or a number with m, h or d: 26h is 93600. Sent as max_age_seconds. Leave it out for failure alerts only
--token-file <path> Read the token from this file, which holds only the token. For a server without the agent, or a user who cannot read agent.env
-- Ends the flags. Everything after it is the command
  • The wrapper is part of the agent package, at /usr/bin/cloudviewer-report.
  • It runs the command first, then sends its exit code and duration in whole seconds, and exits with the command’s exit code.
  • Token: --token-file, else CV_AGENT_TOKEN from the environment, else /etc/cloudviewer-agent/agent.env. Ordinary users cannot read that file, so a job that does not run as root needs --token-file.
  • API URL: CV_AGENT_FACADE_URL, else https://api.cloudviewer.app. When the token comes from agent.env, the URL in that file.
  • Without a token it prints “job ran, not reported” and exits with the command’s exit code.
  • On 429 or 503 it retries once, after Retry-After (at most 60 seconds, 5 if the header is missing). Any other failure prints the HTTP status; the exit code stays the command’s. Each request times out after 15 seconds.
  • A missing --job, a missing command or a bad --max-age is a usage error: exit code 2, and the command does not run.
Status When
Succeeded The last exit code is 0 and the job is not stale
Failed The last exit code is not 0
Stale The job has a max_age_seconds, and its last successful run is older than that. Stale wins over a last exit code of 0

A job that has never succeeded never goes stale, because there is no success to measure from. It shows as Failed, and its row says Never succeeded.

Rule Severity Fires when
UserJobFailed warning The last exit code is not 0, for 5 minutes
UserJobStale warning The last successful run is older than the job’s max_age_seconds, for 5 minutes
  • Cloud Viewer checks every job once a minute.
  • A job without max_age_seconds only gets UserJobFailed.
  • A failed run followed by a successful one within 5 minutes raises no alert. The next successful run resolves both alerts.
  • All rules: Alert rules.