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.

Monitor my script generates a Python or Bash wrapper for your existing job, entirely in your browser.

Follow the Python and Bash setup guide to add the wrapper and check your first run.

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

Validate useful output before reporting success

PulseWatch does not inspect or judge workflow output automatically. Your integration decides when the work is genuinely successful by applying an explicit local rule before it sends /success. If execution raises an exception or the result fails that rule, send /fail and let the job exit as failed.

The rule must fit the workflow. Zero processed records may reveal a broken daily export, while zero may be a legitimate result for a job that only processes new records.

This standard-library example treats an empty daily export as a failure. The check enforces only that specific rule; it does not prove that arbitrary business output is correct.

import os
from urllib.request import urlopen

PING_URL = os.environ["PULSEWATCH_PING_URL"].rstrip("/")
TIMEOUT_SECONDS = 5


def ping(outcome):
    try:
        with urlopen(f"{PING_URL}/{outcome}", timeout=TIMEOUT_SECONDS):
            pass
    except Exception:
        # A monitoring request must not change the job's result or exception.
        pass


ping("start")
try:
    record_count = export_daily_records()
    if record_count < 1:
        raise RuntimeError("daily export produced no records")
except Exception:
    ping("fail")
    raise
else:
    ping("success")

Keep the private ping URL in deployment configuration, as shown here, rather than in source code. Do not put customer data, secrets, or sensitive output in monitor names or failure messages.

Need help choosing a first explicit check? Email support@pulsewatch.ai.

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
No successful run is on record, or the latest success is older than the expected interval plus grace. Before the first success, even a fresh /start or a first /fail is MISSING immediately and can trigger an email on the next applicable check. After a success establishes the baseline, 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, provided the monitor is not missing or stuck. Missing and stuck states take precedence over failure. 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 and sends no alerts. Finish one real run successfully to establish the baseline before relying on missing-run alerts. The first healthy check is silent; later transitions into an unhealthy state or back to OK send emails, except while flapping.

PAUSED means no checks or alerts. Its /start, /success and /fail ping requests return HTTP 409 with status: paused and monitored: false; no run is recorded. Contact support to arrange resuming. Resuming retains history but waits for new pings, using only runs started after resume for health and flapping. Send a fresh start and outcome to establish the new baseline. Upgrading a plan alone does not resume paused monitors.

Billing and support

Support and billing help explains turning off renewal, initial cancellation/refunds and manual account/data requests. These are separate from deleting a monitor. Indie priority support has no guaranteed response time.