Documentation

Watch unattended jobs from the outside.

PulseWatch records a job’s start and outcome, then its separate watchdog service alerts when a job goes missing, fails, or runs too long.

Start here

60-second getting started

Create a monitor in your dashboard and copy its private ping URL. The URL’s token is the monitor credential, so keep it out of public source code and logs.

Example only: https://pulsewatch.example/ping/example-monitor-token

Replace that whole URL with the one shown for your monitor. This is a deliberately fake URL and token.

  1. StartSend /start when the job begins. PulseWatch records the run as in progress.
  2. Finish normallySend /success once the work completes.
  3. Report an errorSend /fail if the job terminates with an error. An optional message query value is saved with the failed run.

Ping endpoints accept GET or POST. A fresh /start supersedes an older unfinished run for the same monitor, so one monitor should represent one active job at a time.

Integration

Python (standard library only)

This example attempts a ping with a 5-second timeout. A monitoring outage will not hang the job or replace the job’s original exception. The failure message is URL-encoded before PulseWatch receives it.

from urllib.parse import urlencode
from urllib.request import urlopen

PING_URL = "https://pulsewatch.example/ping/example-monitor-token"
TIMEOUT_SECONDS = 5


def ping(outcome, message=None):
    url = f"{PING_URL}/{outcome}"
    if message:
        url = f"{url}?{urlencode({'message': message})}"
    try:
        with urlopen(url, timeout=TIMEOUT_SECONDS):
            pass
    except Exception:
        # Monitoring must not interrupt the job it is observing.
        pass


ping("start")
try:
    your_existing_job()
except Exception as exc:
    ping("fail", str(exc))
    raise
else:
    ping("success")

The ping URL is a secret: use your dashboard URL in deployment configuration rather than committing it to a public repository.

Integration

curl / Bash

Do not use set -e around this pattern. It captures the job’s status, reports it, and exits with that same status so a ping cannot turn a failed job into a successful one.

#!/usr/bin/env bash

PING_URL="https://pulsewatch.example/ping/example-monitor-token"

ping() {
  curl --fail --silent --show-error --max-time 5 "$1" >/dev/null || true
}

ping "$PING_URL/start"
./your-existing-job
job_status=$?

if [ "$job_status" -eq 0 ]; then
  ping "$PING_URL/success"
else
  ping "$PING_URL/fail"
fi

exit "$job_status"

Configuration

Expected interval, grace, and max runtime

Expected interval
How often the job should run. PulseWatch expects another successful run within this interval.
Grace
Extra time allowed after the expected interval before a run is MISSING. The missing deadline is expected interval + grace, measured from the start of the latest successful run.
Max runtime
How long a run may remain in progress before it is STUCK. It is independent of the missing deadline: it checks a current /start that has not yet finished.

PulseWatch’s separate watchdog service applies these rules on its scheduled checks, so an alert is sent on the next applicable check after a deadline—not at an exact second.

Example: for a daily job that normally starts around 09:00, use an expected interval of 24 hours, grace of 2 hours, and max runtime of 1 hour. If no later success is recorded, it becomes MISSING after 11:00 the next day. A run still open for more than an hour becomes STUCK.

Timing

Allow for scheduler jitter

A scheduler set to run every 15 minutes does not guarantee that a 15-minute grace is safe. External schedulers, including GitHub Actions, can start late and can occasionally skip or delay runs.

Choose grace from the late starts you actually observe, rather than copying the scheduler’s nominal interval. Leave enough room for normal queueing and platform delays, while keeping it short enough to surface a genuinely missed run.

Reference

Health and alert states

MISSING
Once a monitor has started receiving pings, no successful run has been recorded within the expected interval plus grace. This is the dead-man’s-switch check.
STUCK
At least one run is still running beyond max runtime. This takes precedence over missing and failed states. A run left open beyond the monitor’s orphan age is reported as ORPHANED instead.
FAILED
The most recent completed run ended with /fail. A newer /success returns the monitor to OK, provided it is not missing or stuck.
Flapping
Flapping is not a separate health status. It means terminal runs changed between success and failure at least four times in a rolling two-hour window. PulseWatch suppresses ordinary transition alerts while unstable, sends one flapping alert, then one stabilised alert when the monitor settles.

A monitor with no pings at all is NEVER_RUN; it is not alerted until you have integrated it.