How-to · OpenTelemetry

How to Monitor Cron and Batch Jobs with OpenTelemetry

Monitoring cron and batch jobs means instrumenting each run to emit a span and outcome over OpenTelemetry, so scheduled work that usually runs silently becomes observable and its failures are caught..

Monitoring cron and batch jobs means instrumenting each run to emit a span and outcome over OpenTelemetry, so scheduled work that usually runs silently becomes observable and its failures are caught.

What to observe, and why batch jobs are a blind spot

Scheduled jobs, cron tasks, nightly batches, ETL runs, usually run unattended and fail silently, which is exactly why they are a blind spot: a job that did not start, ran too long, or exited with an error can go unnoticed until something downstream breaks. There is no receiver that watches a job for you; the job has to report on itself, so the approach is instrumentation, not scraping.

The two questions to answer for every scheduled job are simply: did it run when it should have, and did it succeed on time. Everything else, duration, records processed, downstream freshness, hangs off those two.

How OpenTelemetry collects it

You wrap each job execution in an OpenTelemetry span that records its start and end time, exit status and key attributes (records processed, bytes written), and export it over OTLP, which turns a silent schedule into a stream of run records you can query, alert, and act on. For jobs on Kubernetes, the k8sobjects receiver additionally captures Job and CronJob events, so a job that failed to schedule is visible even if it never ran.

The one thing self-reporting cannot catch is a job that never started, because a job that does not run emits no span. So you also track expected schedules and alert on the absence of a run, comparing runs seen against runs expected, which is the only way to detect a missed job.

Because a job must report on itself, the signals below come from per-run spans and from scheduler events, not from a metrics receiver.

Key metrics to watch

The signals that catch most batch-job failures:

SignalHow to captureWhat it tells you / watch for
run occurredper-run span / scheduler eventWhether the job ran when scheduled; the absence of a span is itself the signal.
exit statusspan statusSuccess or failure of each run; a non-zero exit is a failed job.
run durationspan durationHow long the job took; a run exceeding its normal window is an overrun.
records / bytes processedspan attributesThroughput; a run that processes far fewer records than usual may have partially failed.
schedule adherenceexpected vs observed runsA run that should have happened but did not, the failure self-reporting cannot catch.
downstream data freshnessdependent dataset timestampWhether the data the job produces is up to date, the business impact of a missed run.

What to put on a dashboard

A batch-job dashboard is built around presence and outcome. Row one: a grid of jobs showing last-run time and status, with missed runs highlighted (expected but not seen). Row two: run duration against each job's normal window, to catch overruns, and records processed per run. Row three: downstream data freshness, so the business impact of a late or failed job is visible.

# jobs that ran vs jobs that should have run (detect the missing)
count(job.run{result="success"})  by (job)  # compare to expected schedule

# overruns: runs exceeding their normal window
job.run.duration  > job_expected_duration  by (job)

# failed runs
count(job.run{result="failed"})  by (job)

Reading the signals: common failure modes

Missed run

A job that should have run did not, and because a job that does not run emits nothing, it stays invisible unless you are watching for the absence. Comparing expected schedules against observed runs is the only detector. The causes range from a broken scheduler to a disabled cron entry; downstream data going stale is often the first business symptom.

Overrun

A job runs far longer than its normal window, so it either collides with the next scheduled run or delays the data everything downstream depends on. Duration against the expected window flags it. Causes include data-volume growth, a missing index, or resource contention; an overrunning nightly job is a freshness incident, not just a slow log line.

Silent failure or partial run

A job exits with an error, or completes but processes far fewer records than usual, and nobody notices because nothing paged. Exit status and records-processed together catch it. Treat a failed or suspiciously light run as an incident and re-run or investigate, because downstream systems assume the data is complete.

Example alert conditions

Starting conditions to tune:

ConditionSignalMeaning
expected run not seen within its windowscheduleA job was missed.
run exit status = failedfailureA job errored.
run duration > expected windowoverrunA job is running late.
records processed far below normalintegrityA run may have partially failed.

From monitoring to autonomous resolution

Ops Singularity monitors scheduled jobs through TelemetryOps and its DataOps pillar, and resolves run failures, retrying, reallocating or escalating, through governed Action Tickets. Explore TelemetryOps and DataOps.

Frequently asked questions

How do I monitor cron jobs with OpenTelemetry?

Wrap each job run in an OpenTelemetry span recording start, end, exit status and attributes, exported over OTLP. On Kubernetes, the k8sobjects receiver also captures Job and CronJob events.

How do I detect a batch job that did not run?

By tracking expected run schedules against observed run spans, so a missed start is flagged, rather than relying on the job to report its own failure.

See autonomous operations on your own stack.

Bring a real incident. We will show you Sentinel investigate, act and verify end to end, with every action reversible and audited.

Request a Demo → See TelemetryOps