Queries icon
Scan icon
If icon
SquadcastIncomingWebhook icon
SlackIncomingWebhook icon
Log icon
Schedule icon

Data Quality Incident Escalation with Soda

Page on-call when Soda checks fail. Kestra branches on the scan result, opens a Squadcast incident with execution context, and mirrors it to Slack.

Categories
Data

Teams page within minutes when a service goes down, yet a table full of duplicate transactions can sit unnoticed until month-end reconciliation. This blueprint closes that gap by giving data quality the same escalation path as uptime: io.kestra.plugin.soda.Scan runs SodaCL checks with allowFailure: true, an If task inspects {{ outputs.incident_scan.result.hasFailures }}, and failures open a Squadcast incident through io.kestra.plugin.squadcast.SquadcastIncomingWebhook carrying the flow, table, and execution id, with a Slack mirror for the wider team. Clean scans log a quiet all-clear.

How it works

  1. load_transactions (io.kestra.plugin.jdbc.duckdb.Queries) creates and refreshes a small transactions table in the DuckDB file at warehouse_path. It exists so the blueprint runs anywhere; in production you replace it with your real load task.
  2. incident_scan (io.kestra.plugin.soda.Scan) receives the connection through the configuration map, which must define a data source named kestra, and SodaCL checks for row count, missing account ids, and duplicate transaction ids through the checks map. allowFailure: true converts failed checks into a WARNING state, so the flow always reaches the escalation branch. The requirements list adds soda-core-duckdb.
  3. route_incident (io.kestra.plugin.core.flow.If) branches on the hasFailures output. The incident branch first calls page_incident, whose payload sets status to trigger and uses the execution id as event_id, so Squadcast deduplicates repeated pages from the same execution and the incident can later be resolved against the same id.
  4. notify_oncall_channel mirrors the page into Slack with the same context, keeping the wider team informed while on-call works the incident in Squadcast. The clean branch logs the all-clear for the execution history.
  5. The errors block alerts when the escalation flow itself cannot run, and a disabled-by-default morning Schedule trigger scans after the nightly loads.

What you get

  • Data quality failures that page a human through the same on-call machinery as infrastructure failures.
  • Incidents opened with execution context, flow, table, check counts, and a link-ready execution id, instead of a bare alarm.
  • Deduplication for free, since the execution id doubles as the Squadcast event_id.
  • A monitored monitor: a broken escalation flow raises its own Slack alert rather than failing silently.

Who it's for

  • Data platform teams putting data quality on the same on-call rotation as services.
  • On-call engineers who want pages that arrive with enough context to skip the archaeology.
  • Anyone whose worst data incidents were discovered by a customer instead of a monitor.

Why orchestrate this with Kestra

Escalation is a workflow: scan, judge, page, mirror, and keep evidence. Kestra expresses each step as an explicit task, so the paging policy is versioned YAML rather than tribal knowledge. allowFailure plus the If task turn Soda's structured result into a routing decision, the execution history records every judgment including the quiet ones, and the errors block guarantees the escalation path itself is monitored.

Prerequisites

  • A persistent path for the DuckDB file (the warehouse_path input) visible to the task containers. For production warehouses, swap the configuration map to Snowflake, BigQuery, or Postgres and add the matching soda-core-* package to requirements.
  • A Squadcast service with an Incoming Webhook integration, which provides the webhook URL.
  • A Slack incoming webhook for mirrors and flow alerts.

Secrets

  • SQUADCAST_WEBHOOK_URL: Squadcast incoming webhook URL for the target service.
  • SLACK_WEBHOOK_URL: Slack incoming webhook URL.

Quick start

  1. Add the SQUADCAST_WEBHOOK_URL and SLACK_WEBHOOK_URL secrets to your Kestra namespace.
  2. Execute the flow and confirm the log line reports 3 passing checks with no incident.
  3. Change a check to duplicate_count(transaction_id) < 0 and rerun to watch an incident open in Squadcast with the Slack mirror alongside.
  4. Replace load_transactions with your real load task and enable the after_load_window trigger.

How to extend

  • Point the configuration map at Snowflake, BigQuery, or Postgres with credentials from {{ secret('...') }}, and add soda-core-snowflake, soda-core-bigquery, or soda-core-postgres to requirements.
  • Send a second Squadcast payload with status set to resolve and the same event_id from a follow-up flow once a rerun passes, closing the incident automatically.
  • Route different tables to different Squadcast services by splitting the checks across scans, each paired with its own webhook secret.
  • Block downstream work while the incident is open, as shown in the Soda quality gate blueprint.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.