GUIDE · PYTHON · FREE

Monitor Python scripts: a try/except and one HTTP request

Ping on success. Report the exception on failure. Let absence detection catch everything that never reaches your except — the OOM kill, the crashed interpreter, the cron entry that vanished. No SDK, no agent; requests or plain stdlib. Free, no monitor cap.

The snippets

Create a monitor in the console (its schedule = how often the script should run, plus a grace window), copy the ping URL, and wrap your entry point.

With requests

Success pings the monitor URL; an exception POSTs its text to /fail (stored with the ping, 10 KB max) and re-raises so the process still exits non-zero:

import requests PING = "https://ping.lastping.dev/<your-monitor-id>" def main() -> None: ... # your job if __name__ == "__main__": try: main() except Exception as exc: requests.post(f"{PING}/fail", data=str(exc)[:10000], timeout=10) raise else: requests.get(PING, timeout=10)

Standard library only

Zero dependencies — urllib.request sends a GET for success and a POST (a Request with a body) for failure:

from urllib.request import Request, urlopen PING = "https://ping.lastping.dev/<your-monitor-id>" def main() -> None: ... # your job if __name__ == "__main__": try: main() except Exception as exc: urlopen(Request(f"{PING}/fail", data=str(exc)[:10000].encode()), timeout=10) raise else: urlopen(PING, timeout=10)

Optional: overrun detection and run duration

A /start ping arms the hung-job alarm (no success inside the grace window → incident), and a shared rid pairs start with finish so each run's duration is recorded:

import time import requests PING = "https://ping.lastping.dev/<your-monitor-id>" def main() -> None: ... # your job if __name__ == "__main__": rid = str(int(time.time())) requests.get(f"{PING}/start", params={"rid": rid}, timeout=10) try: main() except Exception as exc: requests.post(f"{PING}/fail", data=str(exc)[:10000], timeout=10) raise else: requests.get(PING, params={"rid": rid}, timeout=10)

Why the re-raise matters

raise keeps the exit code non-zero, so whatever runs the script — cron, systemd, a Kubernetes CronJob — still sees the failure and applies its own retry semantics. The ping adds alerting; it never hides the error.


What this catches

The except reports what it can; the silence reports the rest.

  • An exception — the /fail ping opens an incident immediately, with the exception text stored on the ping.
  • A crash your code never sees — OOM kill, segfault in a C extension, kill -9. No success ping arrives; the grace window raises the alert.
  • The script never ran — missing cron entry, broken virtualenv path, dead host. Absence → incident.
  • A hung run — with the /start ping armed, a job stuck on a lock or a dead socket opens an incident inside the grace window.
  • Recovery — the next successful run closes the incident and sends a recovery notice automatically.

Questions people ask

Front-loaded answers — the most important fact first.

  • Do I need a special library or SDK?

    No. A ping is one plain HTTP request — GET, HEAD, or POST. requests is convenient; the standard library's urllib.request works with zero dependencies.

  • What if my script crashes before it can ping?

    That's the point of dead-man's-switch monitoring: a script that segfaults, is OOM-killed, or never starts sends no ping — and the missing ping itself opens the incident after the grace window. The failure path needs no working code.

  • Can I see the exception in the alert trail?

    Yes — POST the exception text as the body of the /fail ping. Up to 10,000 bytes are stored with the ping event and retrievable via the API.

  • Does this work outside plain scripts?

    Anywhere Python runs and can make an HTTP request: a Django management command, a task in a worker, an ETL step, a notebook job. The ping doesn't care what invoked the code.

  • Is this free?

    Yes. LastPing is free and fully hosted with no monitor cap and no paid tier. See how it compares to Healthchecks.io and Cronitor.

FREE · FULLY HOSTED · NO PAID TIER

Your except clause can't catch a missing process.

Six lines now beat a quiet data gap later. First alert wired up in about a minute — and LastPing monitors itself the same way.