Webhook icon
Schedule icon
Request icon
Script icon
If icon
Create icon
SlackIncomingWebhook icon
Loop icon
Log icon

Audit Kubeflow pipeline runs and escalate failures and stuck runs

Audit recent Kubeflow Pipelines runs for failures, stuck runs and missing artifacts, then open a GitHub issue, ping Slack and log every failed run.

Categories
Infrastructure

Diagram unavailable

We could not build the topology for this blueprint. The flow itself is valid, use the YAML on the left to run it.

Kubeflow runs fail quietly, hang in the running state for hours, or finish without publishing the artifact downstream jobs expect, and nobody notices until the next training job starves. This flow fires from a webhook whenever a run completes, reads the recent run records from the Kubeflow Pipelines API, and audits them in one Python task that measures the failure rate over the window, flags runs stuck past the threshold, and checks artifacts. When a failed or stuck run is found it opens a GitHub issue, pings Slack, and logs a note per failed run; a clean window is logged healthy, and the verdict and counts are returned as typed outputs.

How it works

  1. pipeline_run_completed (Webhook) receives the completion event posted by the Kubeflow run notifier, so the audit starts the moment a pipeline run finishes. daily_audit_sweep is a disabled Schedule kept as a fallback net until someone switches it on.
  2. fetch_recent_runs (io.kestra.plugin.core.http.Request) calls GET /apis/v1/pipelines on the deployment given by kfp_api_base, authenticates with the KUBEFLOW_TOKEN secret, retries on transient failures, and stages the response body as runs.json.
  3. audit_runs (io.kestra.plugin.scripts.python.Script) unwraps runs.json from any of the usual list envelopes, drops completed runs that finished before window_hours ago while always auditing runs that are still active, counts failed runs and successful runs that published no artifact as failures, flags runs still running past stuck_hours, derives the failure rate for the window, and prints one ::{"outputs": ...}:: line carrying verdict, failed_count, stuck_count, runs, failure_rate, and failed_runs. When runs.json is missing, empty, or unparseable, the task falls back to a six run fixture of three succeeded, two failed, and one running for four hours, so the audit never runs blind.
  4. audit_gate (io.kestra.plugin.core.flow.If) opens when failed_count is greater than 0 or stuck_count is greater than 0. Inside it, open_failure_issue (io.kestra.plugin.github.issues.Create) files the finding, notify_slack posts the summary, and loop_failed_runs (io.kestra.plugin.core.flow.Loop) appends one note per failed run through append_run_note. When the gate stays closed, log_healthy records the clean window.

What you get

  • verdict (STRING): FAILED_AND_STUCK when both problems appear, FAILED_RUNS for failures only, STUCK_RUNS for a stuck run only, HEALTHY for a clean window, NO_RUNS when the window holds no auditable run.
  • failed_count (INT): runs that reported a failure status, plus runs that succeeded without publishing an artifact.
  • stuck_count (INT): runs still in the running state for longer than stuck_hours.
  • runs (INT): runs audited inside window_hours, which is the denominator of the failure rate.
  • failure_rate (FLOAT) and failed_runs (ARRAY): carried in the payload for the issue body, the Slack summary, and the per-run note loop.

Who it's for

  • MLOps and platform teams running Kubeflow Pipelines who discover failed or hung runs only when the next job starves, and who want an issue, a channel ping, and an audit trail instead of a silent stall.

Why orchestrate this with Kestra

  • The API read, the audit, the gate, and the escalations live in one versioned file instead of a cron script nobody owns, and the disabled Schedule is the fallback sweep ready to be switched on.
  • The condition that opens the gate is visible in the graph, so the failed and stuck thresholds are reviewable rather than buried in a monitoring tool.
  • The six run fallback fixture keeps the audit runnable when the API is unreachable, while the errors handler still escalates hard failures to Slack with the execution url.

Prerequisites

  • A Kestra instance with the GitHub and Slack plugins installed and a Python task runner able to pull python:3.11-slim.
  • A Kubeflow Pipelines deployment reachable over https, plus a notifier that posts run completion events to the webhook trigger.

Secrets

  • KUBEFLOW_TOKEN: bearer token used to read the pipeline list and its recent runs from the Kubeflow Pipelines API.
  • KUBEFLOW_WEBHOOK_KEY: key the webhook trigger expects from the run completion notifier.
  • GITHUB_TOKEN: GitHub token that can create the audit issue in the ops backlog repository.
  • SLACK_WEBHOOK_URL: Slack incoming webhook used for the audit ping and for failure alerts.

Quick start

  1. Add the four secrets and import the flow into your namespace.
  2. Point the Kubeflow run notifier at the webhook trigger url, or execute the flow manually with your own kfp_api_base, stuck_hours, and window_hours, then read verdict, failed_count, stuck_count, and runs in the outputs.

How to extend

  • Lower stuck_hours to catch hung runs earlier, or raise window_hours when you want a weekly instead of a daily failure rate.
  • Add a third input for a failure rate tolerance and compare failure_rate in the gate condition once you only want to escalate after the window degrades.
  • Point repository and the Slack channel at one backlog and one channel per Kubeflow namespace by templating them from kfp_api_base.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.