opsbeginner5 min setupby Mantle

Scheduled health check with email alert

Ping an endpoint every 5 minutes; if it does not return 200, email the on-call address with the status code.

Every 5 minutesGET /healthHealthy?Alert on-callHealthy — stop

Drag to pan, pinch to zoom. This is the real graph the template installs.

Purpose

Ping an endpoint every 5 minutes; if it does not return 200, email the on-call address with the status code.

How it works

What it does

  • Every 5 minutes, GET the health URL (one retry after 2 s).
  • Healthy? routes a non-200 status to Alert on-call; a 200 ends quietly.
  • The dashed error edge from the request also alerts when the request itself fails (timeout, DNS).

Nodes 5

  1. 01Every 5 minutestrigger.scheduleTrigger
  2. 02GET /healthhttp.requestHTTP
  3. 03Healthy?control.branchLogic
  4. 04Alert on-callmail.sendDestination
  5. 05Healthy — stopcontrol.filterLogic
View template JSON
{
  "format": "mantle-workflow/v1",
  "id": "ops-http-health-check",
  "name": "Scheduled health check with email alert",
  "graph": {
    "nodes": [
      {
        "id": "schedule",
        "type": "trigger.schedule",
        "label": "Every 5 minutes",
        "config": {
          "interval_sec": 300,
          "timezone": "UTC"
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 60,
          "y": 220
        }
      },
      {
        "id": "ping",
        "type": "http.request",
        "label": "GET /health",
        "config": {
          "method": "GET",
          "url": "https://example.com/health",
          "timeout_seconds": 10
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 380,
          "y": 220
        },
        "retry": {
          "max_attempts": 2,
          "backoff": "fixed",
          "initial_ms": 2000,
          "max_ms": 2000
        }
      },
      {
        "id": "branch_healthy",
        "type": "control.branch",
        "label": "Healthy?",
        "config": {
          "mode": "first_match"
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 700,
          "y": 220
        }
      },
      {
        "id": "send_alert",
        "type": "mail.send",
        "label": "Alert on-call",
        "config": {
          "to": "oncall@example.com",
          "subject": "[ALERT] health check failed ({{ steps.ping.status_code }})",
          "body_text": "GET https://example.com/health returned {{ steps.ping.status_code }} at {{ $now }}.\n\nBody:\n{{ steps.ping.body }}"
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 1020,
          "y": 410
        }
      },
      {
        "id": "all_good",
        "type": "control.filter",
        "label": "Healthy — stop",
        "config": {
          "expr": "status_code == 200"
        },
        "worker_type": "generic-worker",
        "position": {
          "x": 1020,
          "y": 30
        }
      }
    ],
    "edges": [
      {
        "from": "schedule",
        "to": "ping"
      },
      {
        "from": "ping",
        "to": "branch_healthy"
      },
      {
        "from": "branch_healthy",
        "to": "send_alert",
        "branch": "true",
        "condition": {
          "match": "all",
          "rules": [
            {
              "left": "status_code",
              "op": "not_equals",
              "right": 200
            }
          ]
        },
        "label": "not 200"
      },
      {
        "from": "branch_healthy",
        "to": "all_good",
        "branch": "false",
        "label": "200 OK",
        "priority": 1
      },
      {
        "from": "ping",
        "to": "send_alert",
        "branch": "error",
        "label": "request failed"
      }
    ]
  }
}

Requirements

The connections and permissions each step needs, from the node contracts in the catalog.

  • SendGridAPI key

    Used by Alert on-call.

    Credential: {"api_key"} or {"username", "password"}

Setup

  • Change the url on GET /health and the interval_sec on the trigger.
  • Set the recipient and a SendGrid / SMTP connection on Alert on-call.

Sample input and output

Synthetic examples: node-contract samples or placeholders, never customer data.

Input

Runs every 5 min (UTC). There is no incoming payload: the first step fetches the data.

Output

Alert on-call mail.send

{
  "body": null,
  "message_id": "",
  "provider": "",
  "sent": true,
  "status_code": 0,
  "thread_id": ""
}

Healthy — stop control.filter

{}

Failure handling

What the graph does when a step fails, read from its retry settings, error branches and error policies.

  • GET /health: up to 2 attempts, 2 s between attempts.
  • GET /health: the request times out after 10 s.
  • If GET /health still fails, the error branch runs Alert on-call with the error and the step's input.
  • Any other step that fails, after its retries, fails the run. The failed step is kept with its input and error.

See it run, then make it yours.

Templates install as drafts. Edit any step, and Workflow Health re-checks the graph on every save.