WhatPing

How WhatPing works

Monitoring is a system that has to be more reliable than the things it watches, which makes its architecture worth stating rather than hiding. This page describes what actually runs.


Three parts

1. A stateless probe worker, in Rust. It fetches its configuration from the backend, runs HTTP and TCP checks on schedule, and submits raw observations. It stores nothing. It decides nothing. Concurrency is bounded by a semaphore so a burst of due checks cannot exhaust the host, and shutdown drains in-flight probes rather than dropping them.

Because it holds no state, restarting it mid-outage is a non-event: no incident is lost, no duplicate is created, and no counter resets.

2. A backend that owns every decision. Configuration and current state live in the same place. The worker says “this check failed at this time”; the backend decides whether that means the monitor is down, whether an incident opens, and which alerts fire. One place to reason about, and one place where a bug can be fixed for every monitor type at once.

3. Scheduled checks for the things with expiry dates. Certificates, domain registrations, DNS records and email authentication run on a daily schedule from the backend rather than through the prober. A certificate does not stop being valid between one minute and the next; polling it every 60 seconds would produce the same answer 1,440 times a day.


Idempotency

Every check result carries an ID generated by whoever produced it. If the worker submits a batch, loses the connection before it sees the response, and retries — the backend recognises the replay and discards it.

This is why a network blip cannot open two incidents for one outage, and cannot page you twice for the same failure. It is a small mechanism that removes an entire category of “why did I get four alerts” that is otherwise very hard to reason about after the fact.


A dead man’s switch on the prober

The uncomfortable question for any monitoring system is what happens when the part that runs the checks dies. If that component also decides whether things are overdue, then when it dies it stops noticing anything — including itself. Everything goes quiet, and quiet looks like healthy.

So heartbeat deadlines are evaluated in the backend, on a schedule, in a different process on different infrastructure from the prober. The prober sends its own heartbeat like any other job. If it stops, the backend notices and alerts.

This is not a hypothetical. A configuration-parsing bug once froze the worker on a stale snapshot — it kept probing the old configuration and looked completely normal from outside. The heartbeat monitor was the only signal that anything was wrong, and it fired within ten minutes.


Alerting is downstream of state

Notifications are dispatched only after monitor state has been committed, and every delivery attempt is recorded rather than thrown.

The property this buys: a broken alert channel can never corrupt your monitoring. A webhook that 500s forever, an SMTP server that is refusing connections, a Telegram token that was revoked — all of them are recorded failures against a monitor whose state is unaffected.


What runs where

Component What it is Notes
Probe worker Rust, systemd unit Stateless, bounded concurrency, graceful drain
Backend Convex, on our own infrastructure Owns configuration, state, incidents, alert dispatch, scheduled checks
Dashboard Next.js Server-rendered, behind authentication
Ingress Cloudflare named tunnel No inbound ports open on the host

The honest limitation

Checks run from one network location. WhatPing does not have probes in twelve regions, and the site will not pretend otherwise. The second opinion gives you one independent confirmation per incident, which distinguishes “the target is down” from “our path to the target is broken” — but it is one extra vantage point, not a fleet.

If your requirement is genuinely regional — you need to know that your service is unreachable from Singapore specifically — that is a real requirement and WhatPing does not meet it today.

Read the docs