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.
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
- 01Every 5 minutestrigger.scheduleTrigger
- 02GET /healthhttp.requestHTTP
- 03Healthy?control.branchLogic
- 04Alert on-callmail.sendDestination
- 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
urlon GET /health and theinterval_secon 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.