Uptime Monitoring

Depfloy watches two different things in two different ways. A health check requests a URL on a schedule and reads the answer. A heartbeat waits for a job to report in, and reaches its verdict from the silence when no report arrives.

Two kinds of monitor #

A health check is a request Depfloy makes to a URL. It needs the thing it watches to answer from the internet, and it is the one that catches a site that is up but wrong — an application whose process is running while every page returns a 500.

A heartbeat is a report the watched job sends to Depfloy. Nothing can request a nightly cron or a queue worker, so they announce themselves instead, and a missing announcement is the alarm. A machine that loses power stops reporting; so does a cron daemon that was stopped during maintenance and never started again.

Both live in one list under Uptime in the Console, both use the same notification settings, and both follow the same rules about when a problem is worth telling you about.

Health checks #

Creating one #

Open Uptime and click New health check:

  • Name — what the monitor is called in the list and in notifications.
  • Project — the project this monitor belongs to. Who can see the monitor follows from who can already reach that project.
  • URL — the address to request. Picking a project fills this in from its primary domain, and it stays editable: point it at a path such as /health, or at a domain other than the primary one. A project with no active domain yet leaves the box empty for you to fill in.
  • Expected status — optional. Leave it blank and any 2xx answer counts as healthy.

What counts as a failure #

  • The request does not complete: DNS does not resolve, the connection is refused, TLS fails, or the response does not arrive within the timeout (10 seconds by default).
  • The response arrives with a status that is not the one you asked for — or, when you left the field blank, one outside 2xx.

Redirects are not followed. A URL that answers 301 is a failure unless 301 is what you named as the expected status. When a site’s address moves, the redirect is usually the thing worth knowing about.

A site behind a bot challenge #

A health check is an unattended request from a Depfloy server, which is exactly what bot protection is built to stop. A site behind Cloudflare’s bot fight mode, a managed challenge or a WAF rule can answer the check with a 403 and a challenge page while every browser on the planet loads it fine.

Depfloy recognises that answer rather than reporting a bare status code that sends you looking for an outage that is not there. The monitor’s page says what the response showed, and carries the Cloudflare Ray ID of the challenged request — search it under Security → Events and Cloudflare names the service that acted.

Which service it is decides what fixes it. Cloudflare judges the request by the address it came from rather than its user agent, so a WAF rule that merely matches Depfloy-Monitor changes nothing on its own: its action has to skip the product that issued the challenge. Bot Fight Mode accepts no skips at all — it is turned off, or moved to Super Bot Fight Mode, which does. Pointing the check at a path your rules leave alone works whatever the answer turns out to be.

Depfloy does not write that rule for you. The Cloudflare token it asks for covers zones and DNS records, and nothing in your security settings.

A 401 or 403 with no challenge behind it gets the same treatment, as does a 429. A failure with no cause the response states outright — a 500, say — is reported as what it is and nothing more.

How often it runs #

How often a check runs depends on the plan:

PlanFastest check
StarterEvery 5 minutes
ProEvery 60 seconds
BusinessEvery 60 seconds

A monitor may always ask for something slower — up to a day — and the request method, the timeout and the number of failures it takes to report an outage can be set through the API on a per-monitor basis.

The floor applies to the check itself, not only to what you may type. A monitor created on a faster plan keeps the interval you chose, and is checked at your current plan’s frequency until you move back up — at which point your number takes effect again with nothing to re-enter. GET /api/v1/monitors/options reports the range your plan allows.

Heartbeats #

A heartbeat is turned on from the job it watches, not from the Uptime screen — the report has to come from that specific job.

Open a project’s Schedulers or Background Jobs tab, or the same sections on a server, and pick Turn on heartbeat from the job’s menu. Depfloy weaves the reporting into that job for you: there is nothing to add to a crontab line and no package to install. Turn off heartbeat removes the monitor and takes the reporting back out.

The job’s row then carries a Heartbeat badge, which becomes Not reporting while the monitor is down.

What a scheduled job reports #

A scheduled job reports three things: that it started, and then either that it finished cleanly or that it failed. So a job that runs but exits non-zero is distinguishable from one that never ran at all, and the notification says which happened.

Reporting cannot break the job. If Depfloy is unreachable when the job finishes, the report is dropped and the job’s own exit code is preserved — a failed report never turns a successful run into a failed one, and never the reverse.

What a background job reports #

Background jobs are watched by a listener installed alongside the process supervisor on that server. It reports when a process starts, stops or exits, and sends a periodic all-is-well signal in between. Because the signal is periodic, a supervisor that stops entirely is caught too: the reports stop arriving and the monitor goes down like any other silence.

Turning a heartbeat on does not restart the job it watches.

Schedules that cannot be watched #

A schedule that fires on an event rather than an interval — @reboot — has no heartbeat option, because there is no window in which a report is late. Every other schedule can be watched, and background jobs always can.

How often a report is expected #

You are not asked how often the job runs. Depfloy reads it from the job’s own schedule, so the monitor and the crontab cannot disagree about it. Late is measured with a grace period on top: half the interval, and never less than a minute. An hourly job is late 90 minutes after its last report rather than on the stroke of the hour, and the confirmation rule below decides when being late becomes an outage.

A background job’s listener reports every minute, so a stopped process is late after three and a half.

When a monitor is reported down #

One failure is not an outage. A monitor is reported down after three consecutive failures by default, so a single network hiccup or one slow second on the far end passes without a message. The number is configurable per monitor between 1 and 10 through the API.

Recovery is the mirror of it, with one deliberate difference:

  • A health check must answer correctly twice in a row before it is called healthy again. A service answering one request in two would otherwise produce an alarm and an all-clear every minute.
  • A heartbeat recovers on the first report. A report is not a sample of something that fluctuates — it is the job saying it ran. Waiting for a second one would keep a fixed nightly job marked down for another day.

A new monitor starts quiet #

A monitor you have just created reads Awaiting first check until it has enough evidence. A monitor that turns out to be healthy sends nothing — there was no outage to recover from. A target that is broken from the moment you start watching it does send a notification, because that is news.

Turning a monitor off and on again puts it back in the same state, with its counters cleared, rather than resuming an opinion formed weeks ago.

Notifications #

Outages and recoveries use your existing notification settings. Monitor Down and Monitor Recovered are separate switches per channel: email is on by default, Slack is off until you connect a workspace and turn it on.

When one event takes several monitors with it — a server going offline takes every site on it — the messages are collected into one, so twenty monitors going down produce one notification listing twenty, not twenty notifications.

A recovery message says how long the outage lasted.

Reading the list #

Uptime lists every monitor you can see, the ones that are down first. Each row carries a status dot, the target, the type, how long it has been in its current state, and its uptime over the last 24 hours and 7 days. The search box filters by name or target, and the dropdown narrows the list to health checks or heartbeats.

The list updates itself as statuses change — an outage that resolves while you are reading updates in place, without moving what you are looking at.

Open a monitor for its uptime figures and its event history: when each outage started, when it was resolved, and what the failure was.

Edit changes a monitor’s name, and for a health check the URL it requests and the status it expects. Uptime already recorded stays with the monitor, so the figures after a URL change cover both addresses.

A monitor’s type and the project or job it belongs to are fixed when it is created. To watch something else, create a monitor for it — the history on the existing one belongs to what it has been watching all along.

Deleting a monitor #

Open the monitor and click Delete. Its event history goes with it. For a heartbeat, this also removes the reporting from the job — the same as Turn off heartbeat on the job itself.

What your plan includes #

Limits are per type, so a Starter plan gets one of each rather than one in total.

PlanHealth checksHeartbeats
Starter11
Pro1010
BusinessUnlimitedUnlimited

Only active monitors count. Turning one off frees its place, and turning it back on takes it again — if the space is gone by then, the request is refused and says so.

Who can do what #

OwnerAdminManagerDeveloperViewer
View health checks and heartbeats✓✓✓✓
Create, turn on/off, and delete them✓✓✓

A member sees the monitors whose project or server they can already reach, which is the same rule the rest of the Console follows. See Members.

API #

Monitors are available at /api/v1/monitors. Reading needs monitor:read; creating, updating and deleting need monitor:manage.

GET /api/v1/monitors List monitors
cURL
curl https://app.depfloy.com/api/v1/monitors \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"

type and status narrow the list; results are paginated 25 at a time. Every monitor comes back with current_status, last_status_changed_at, uptime_24h and uptime_7d, and a single monitor comes back with its last 50 events.

Creating a health check takes the target and the settings together:

POST /api/v1/monitors Create a health check
cURL
curl https://app.depfloy.com/api/v1/monitors \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "http",
    "name": "Storefront",
    "monitorable_type": "App\\Models\\Project",
    "monitorable_id": 412,
    "config": {
      "url": "https://shop.example.com",
      "method": "GET",
      "expected_status": 200,
      "interval_seconds": 300,
      "timeout_seconds": 10,
      "confirmation_threshold": 3
    }
  }'

A heartbeat is created against a scheduled job or a background job, and needs no config — the schedule supplies the timing:

POST /api/v1/monitors Create a heartbeat
cURL
curl https://app.depfloy.com/api/v1/monitors \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "heartbeat",
    "name": "Nightly invoices",
    "monitorable_type": "App\\Models\\SchedulerJob",
    "monitorable_id": 87
  }'

A health check can also be attached to a domain instead of a project — pass App\\Models\\Domain as the monitorable_type. The Console creates health checks against projects; both are available over the API.

GET /api/v1/monitors/options returns the monitor types and the targets each one accepts, so a client can build its own form without hardcoding the list.

PUT /api/v1/monitors/{id} changes the name, the config, the notification channels, and is_active. type, monitorable_type and monitorable_id are rejected — those are settled at creation. config is replaced rather than merged, so send the settings you are keeping alongside the ones you are changing.