OCNORA
utilitiesintermediate10 min setupby Mantle

Delay, retry and dead-letter

Call a flaky endpoint with backoff retries; on final failure wait, try a fallback endpoint, and if that also fails email an operator.

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

How it works

What it does

  • Primary endpoint retries 4× with exponential backoff (1 s → 20 s cap).
  • Only if it still fails does the dashed error edge fire: Wait 60sFallback endpoint (2 fixed retries).
  • If the fallback fails too, Dead-letter to operator emails the payload.

Setup

  • Set both urls and the operator address (SendGrid/SMTP connection). Success paths end silently — add downstream nodes to either call as needed.

Nodes 5

  1. 01Job intrigger.webhookTrigger
  2. 02Primary endpointhttp.requestHTTP
  3. 03Wait 60scontrol.delayLogic
  4. 04Fallback endpointhttp.requestHTTP
  5. 05Dead-letter to operatormail.sendDestination
View template JSON
{
  "format": "mantle-workflow/v1",
  "id": "util-delay-retry-webhook",
  "name": "Delay, retry and dead-letter",
  "graph": {
    "nodes": [
      {
        "id": "webhook",
        "type": "trigger.webhook",
        "label": "Job in",
        "config": {
          "slug": "flaky-job",
          "idempotency_path": "job_id"
        },
        "connection_id": null,
        "worker_type": "generic-worker",
        "position": {
          "x": 60,
          "y": 220
        }
      },
      {
        "id": "primary_call",
        "type": "http.request",
        "label": "Primary endpoint",
        "config": {
          "method": "POST",
          "url": "https://primary.example.com/jobs",
          "body_from_input": true,
          "timeout_seconds": 10
        },
        "connection_id": null,
        "worker_type": "generic-worker",
        "position": {
          "x": 380,
          "y": 220
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exp",
          "initial_ms": 1000,
          "max_ms": 20000
        }
      },
      {
        "id": "cool_down",
        "type": "control.delay",
        "label": "Wait 60s",
        "config": {
          "seconds": 60
        },
        "connection_id": null,
        "worker_type": "generic-worker",
        "position": {
          "x": 700,
          "y": 410
        }
      },
      {
        "id": "fallback_call",
        "type": "http.request",
        "label": "Fallback endpoint",
        "config": {
          "method": "POST",
          "url": "https://fallback.example.com/jobs",
          "body_from_input": true,
          "timeout_seconds": 10
        },
        "connection_id": null,
        "worker_type": "generic-worker",
        "position": {
          "x": 1020,
          "y": 410
        },
        "retry": {
          "max_attempts": 2,
          "backoff": "fixed",
          "initial_ms": 5000,
          "max_ms": 5000
        }
      },
      {
        "id": "dead_letter",
        "type": "mail.send",
        "label": "Dead-letter to operator",
        "config": {
          "to": "ops@example.com",
          "subject": "Job {{ steps.webhook.job_id }} failed on primary and fallback",
          "body_text": "Payload:\n{{ steps.webhook }}"
        },
        "connection_id": null,
        "worker_type": "generic-worker",
        "position": {
          "x": 1340,
          "y": 600
        }
      }
    ],
    "edges": [
      {
        "from": "webhook",
        "to": "primary_call"
      },
      {
        "from": "primary_call",
        "to": "cool_down",
        "branch": "error",
        "label": "primary failed"
      },
      {
        "from": "cool_down",
        "to": "fallback_call"
      },
      {
        "from": "fallback_call",
        "to": "dead_letter",
        "branch": "error",
        "label": "fallback failed"
      }
    ]
  }
}

Use it, then make it yours.

Templates install as drafts. Change anything, and Workflow Health re-checks the graph on every save.