New to Kestra?
Use blueprints to kickstart your first workflows.
Detect failing ClickHouse mutations in system.mutations, kill them behind a dry-run and approval gate, then re-read to confirm none are still pending.
An async ClickHouse mutation (ALTER TABLE ... UPDATE or DELETE) can wedge. A bad expression makes it throw on every retry, so it sits in system.mutations with is_done = 0 and a latest_fail_reason, blocking later mutations on the same table and holding merge resources. This guard finds those mutations and kills the failing ones under a gate, then proves none are still pending.
This blueprint was created by zkasuran.
dry_run is true and auto_remediate is false, so a plain run reports and never kills.auto_remediate is true and dry_run is false. It then waits for a human to resume the Pause with approved set true. An unanswered gate reads as not approved.include_stuck_without_failure, because killing it would discard the work it has already done.detect (io.kestra.plugin.jdbc.clickhouse.Query) reads system.mutations for the database and keeps rows with is_done = 0 that either have a non empty latest_fail_reason or, when include_stuck_without_failure is true, were created more than stuck_minutes ago.summarize (io.kestra.plugin.core.output.OutputValues) records the targeted mutation list and the fail reasons once, so the log, the alert and the failure message all read the same value.log_detect (io.kestra.plugin.core.log.Log) prints the count, the mutation ids and the fail reasons.guard (io.kestra.plugin.core.flow.If) branches on the targeted count. With none found, clean logs and the run ends.findings_alert (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) posts the wedged mutations on every detection, in dry run and in remediate mode.mode (io.kestra.plugin.core.flow.If) enters the remediation branch only when auto_remediate is true and dry_run is false. Otherwise report_only lists what would be killed and stops.approval_gate (io.kestra.plugin.core.flow.Pause) holds the run until a human resumes it with approved. apply runs the kill only when approved is true.remediation_kill_loop (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) runs KILL MUTATION WHERE database = ... AND table = ... AND mutation_id = ... once per targeted mutation.reverify re-reads system.mutations with the same filter. verify_result then fails the run through io.kestra.plugin.core.execution.Fail if any targeted mutation is still is_done = 0.system.mutations, so it catches the exact mutations that retry forever and block the queue.system.mutations shows zero targeted mutations.ClickHouse has no scheduler, no approval step and no way to prove a KILL MUTATION took effect. Kestra adds the missing pieces. It schedules the sweep, gates the kill behind dry-run and approval, re-reads system.mutations to turn a hopeful kill into a verified one, applies the same connection settings to every task and posts a Slack alert the moment a step fails.
Run on Kestra 2.0.5 against a ClickHouse 24.8 server. A MergeTree table of five rows was wedged with a real failing mutation (ALTER TABLE ... UPDATE amount = toUInt64(raw) where raw holds non numeric strings), confirmed stuck in system.mutations with is_done = 0 and a Cannot parse fail reason.
clickhouse-client against system.mutations).is_done = 0 afterwards).system.mutations).approved false killed nothing.A ClickHouse server reachable over the JDBC HTTP interface and a user that can read system.mutations and run KILL MUTATION on the target tables.
CLICKHOUSE_USERNAME: ClickHouse user, read when use_secret_auth is true.CLICKHOUSE_PASSWORD: password for that user.SLACK_WEBHOOK_URL: used by findings_alert and the errors block.SECRET_.| Name | Type | Default | Description |
|---|---|---|---|
clickhouse_url |
STRING | jdbc:clickhouse://localhost:8123/default |
ClickHouse JDBC URL. |
use_secret_auth |
BOOL | true |
Read credentials from secrets. Set false only for inline test credentials. |
database |
STRING | default |
Database whose mutations are checked. |
table |
STRING | "" |
Optional single table filter. Empty checks every table. |
stuck_minutes |
INT | 30 |
Age threshold for a mutation with no fail reason. |
include_stuck_without_failure |
BOOL | false |
Also target slow mutations past the age threshold. |
dry_run |
BOOL | true |
Report without killing. |
auto_remediate |
BOOL | false |
Kill behind the approval gate when dry_run is false. |
CLICKHOUSE_USERNAME, CLICKHOUSE_PASSWORD and SLACK_WEBHOOK_URL as namespace secrets.database pointed at a ClickHouse database. The default dry run reports the stuck or failing mutations.dry_run false and auto_remediate true, then resume the paused execution with approved true.include_stuck_without_failure true to also clear mutations that have no fail reason but have not finished within stuck_minutes.