Schedule icon
Webhook icon
Assert icon
Request icon
Script icon
If icon
SlackIncomingWebhook icon
Pause icon
Loop icon
Sleep icon
Fail icon
Log icon
Set icon

Terminate Argo Workflows Stuck in the Running Phase After Approval

Detect Argo Workflows stuck in the Running phase, alert Slack, and terminate with operator approval and verification in Kestra.

Categories
DataInfrastructure

Argo Workflows executes each step of a workflow as a Kubernetes Pod. When that pod is evicted by the node's kubelet under memory pressure, killed by a node drain during a cluster upgrade, or otherwise removed outside of Argo's own control, the workflow controller can lose track of it. The workflow object is left in the Running phase indefinitely: not failed, not succeeded, just silently stalled, with no further node transitions and no natural end. Nothing in Argo itself pages anyone when this happens, and a stuck workflow can sit there consuming a slot in dashboards and metrics until someone notices it manually.

This blueprint provides an automated guard that lists workflows in a namespace via the Argo Server REST API, flags any still in the Running phase after max_running_hours has elapsed since status.startedAt, requests human approval, calls Argo's terminate API, and re-fetches the workflow to confirm it actually left the Running phase.

How it works

  1. Pre-flight Assertion: validate_inputs (io.kestra.plugin.core.execution.Assert) checks that the running-hours threshold and the per-run termination cap are both positive.
  2. Workflow Discovery: list_workflows (io.kestra.plugin.core.http.Request) calls GET /api/v1/workflows/{namespace} on the Argo Server API, authenticated with a Bearer token.
  3. Triage: triage_workflows (io.kestra.plugin.scripts.python.Script) filters for status.phase == "Running", excludes any workflow whose name matches exclude_workflow_name_prefixes, and flags the remainder whose elapsed time since status.startedAt is at or beyond max_running_hours. Candidates beyond max_terminations_per_run are deferred to a later run, prioritizing the longest-running ones first. Running time is monotonic and a terminated workflow naturally leaves the Running phase it was flagged in, so unlike a flapping reachability signal, this detection needs no cross-run state to avoid false positives.
  4. Slack Triage Alert: When stuck workflows exist, dispatch_slack_alert posts the affected workflow names, namespace, and hours running.
  5. Human Approval Gate: When auto_remediate is enabled and dry_run is false, pause_for_operator_approval (io.kestra.plugin.core.flow.Pause) halts execution until an operator resumes with approved: true.
  6. Terminate and Verify: terminate_stuck_workflows (io.kestra.plugin.core.flow.Loop) calls PUT /api/v1/workflows/{namespace}/{name}/terminate per approved workflow, waits briefly, re-fetches the workflow, and fails loudly via io.kestra.plugin.core.execution.Fail if it still reports phase Running.
  7. Audit & Resolution: The audit manifest is archived in Kestra KV for compliance history, and a resolution card is posted to Slack.
  8. Failure Handling: A flow-level errors block alerts Slack if Argo Server connectivity, bearer token validity, or scripting fails unexpectedly.

What you get

  • Automated detection of Argo Workflows silently stuck in the Running phase after a pod eviction or node drain.
  • A per-run termination cap that prioritizes the longest-stuck workflow first instead of terminating a whole batch at once.
  • Human-in-the-loop approval before any workflow is terminated.
  • Post-termination verification that fails loudly instead of assuming the terminate call worked.
  • A name-prefix exclusion list so legitimately long-running workflows are never touched.

Who it's for

  • Platform Engineers and SREs operating Argo Workflows for CI, data, or ML pipelines on Kubernetes.
  • Teams running node auto-scaling or spot/preemptible node pools, where pod eviction is a routine occurrence that can orphan a workflow.
  • On-call engineers who want stuck workflows surfaced and cleared without manually scanning argo list output.

Why orchestrate this with Kestra

Argo Workflows has no built-in alert for a workflow stuck in the Running phase, and nothing automatically terminates one even when its pods are long gone. Kestra adds declarative scheduling, a threshold check against the real startedAt field, an interactive approval gate, and verified, auditable termination on top of the raw Argo Server API.

Prerequisites

  • A reachable Argo Server (Argo Workflows 3.x or higher) with its API port (default 2746) reachable from the Kestra worker.
  • A Kubernetes ServiceAccount bearer token (or equivalent) with permission to list and terminate workflows in the target namespace.
  • A Slack Incoming Webhook URL for triage and resolution notifications.

Secrets

  • ARGO_BEARER_TOKEN: A Kubernetes ServiceAccount bearer token authorized against the Argo Server API.
  • SLACK_WEBHOOK_URL: Slack Incoming Webhook endpoint for triage and resolution alerts.
  • ARGO_GUARD_WEBHOOK_KEY: Secret authentication token protecting the on-demand webhook trigger.

Quick start

  1. Configure ARGO_BEARER_TOKEN, SLACK_WEBHOOK_URL, and ARGO_GUARD_WEBHOOK_KEY in your Kestra namespace secrets.
  2. Import this blueprint and set argo_server_url and argo_namespace to match your cluster.
  3. Run a manual execution with the default dry_run: true to audit currently Running workflows without mutating anything.
  4. Review the execution logs and Slack triage card, and set exclude_workflow_name_prefixes for any legitimately long-running workflows.
  5. Run with auto_remediate: true and dry_run: false to arm remediation; when stuck workflows are detected, approve the pause_for_operator_approval task with approved: true and observe the verified termination.
  6. Enable the periodic_stuck_workflow_audit schedule trigger for continuous monitoring.

How to extend

  • Node-Level Confirmation: Before terminating, add a Kubernetes API call checking whether the workflow's pods actually still exist, to distinguish a truly orphaned workflow from one that is merely slow.
  • Auto-Resubmit: After a verified termination, chain a call to POST /api/v1/workflows/{namespace}/{name}/resubmit to automatically retry the work under a new workflow name, when the underlying job is safe to rerun.
  • PagerDuty Escalation: Add io.kestra.plugin.pagerduty.PagerDutyAlert when a workflow has been stuck for multiples of max_running_hours, signaling a recurring eviction pattern worth deeper investigation.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.