New to Kestra?
Use blueprints to kickstart your first workflows.
Detect ClickHouse partitions past a retention window in system.parts, drop them behind a dry-run and approval gate, then re-read to confirm.
ClickHouse MergeTree tables keep old partitions on disk when no TTL is set or when a TTL exists but its DELETE was never materialized by a merge. Storage then grows past the retention policy while every query still pays to skip the dead parts. This guard finds those partitions and drops them under a gate, then proves the drop landed.
This blueprint was created by zkasuran.
dry_run is true and auto_remediate is false, so a plain run reports and never drops.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.system.parts, so a partition whose age cannot be read (a non temporal partition key) is skipped and never dropped.detect (io.kestra.plugin.jdbc.clickhouse.Query) reads system.parts for the table, groups active parts by partition and keeps partitions whose newest row is older than now() - retention_days. It reads the newest row as greatest(max(max_time), toDateTime(max(max_date))), correct for toYYYYMM, toDate and toYYYYMMDD partition keys. That same value must also be above the epoch floor, so a non temporal key is never selected.summarize (io.kestra.plugin.core.output.OutputValues) records the expired partition id list once for the logs, the alert and the failure message.guard (io.kestra.plugin.core.flow.If) branches on the expired count. With none found, clean logs and the run ends.findings_alert (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) posts the breach 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 dropped and stops.approval_gate (io.kestra.plugin.core.flow.Pause) holds the run until a human resumes it with approved. apply runs the drop only when approved is true.drop_expired_partitions (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) runs ALTER TABLE ... DROP PARTITION ID once per expired partition.reverify re-reads system.parts with the same window. verify_result then fails the run through io.kestra.plugin.core.execution.Fail if any expired partition is still present.system.parts, not the partition key format, so it works across date and datetime partition keys.system.parts shows zero expired partitions.ClickHouse has no scheduler, no approval step and no way to prove a maintenance command took effect. Kestra adds the missing pieces. It schedules the sweep, gates the destructive statement behind dry-run and approval, re-reads system.parts to turn a hopeful drop 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 with a toYYYYMM(ts) table seeded with three 2024 partitions and two recent ones.
clickhouse-client).system.parts).approved false dropped nothing.A ClickHouse server reachable over the JDBC HTTP interface and a user that can read system.parts and run ALTER TABLE ... DROP PARTITION on the target table.
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 holding the table. |
table |
STRING | events |
MergeTree table to guard. |
retention_days |
INT | 90 |
A partition is expired when its newest row is older than this. |
dry_run |
BOOL | true |
Report without dropping. |
auto_remediate |
BOOL | false |
Drop behind the approval gate when dry_run is false. |
CLICKHOUSE_USERNAME, CLICKHOUSE_PASSWORD and SLACK_WEBHOOK_URL as namespace secrets.database and table pointed at a partitioned MergeTree table. The default dry run reports the expired partitions.dry_run false and auto_remediate true, then resume the paused execution with approved true.DROP PARTITION with MOVE PARTITION ... TO DISK to tier old data to object storage instead of deleting it.