id: iceberg-partition-compaction-and-maintenance-gate
namespace: company.lakehouse
description: |
Autonomous Lakehouse partition maintenance gate for Apache Iceberg and Delta Lake tables.
Profiles Parquet file distributions in DuckDB to measure small file fragmentation ratio and
metadata bloat, conditionally triggers bin-packing compaction and snapshot expiration only on
degraded partitions, and dispatches an itemized Lakehouse Health Scorecard to Slack.
inputs:
- id: seed_demo_data
type: BOOL
defaults: true
description: When true, generates synthetic partitioned Lakehouse file metadata
with realistic small-file fragmentation for zero-setup execution.
- id: small_file_threshold_mb
type: INT
defaults: 64
description: Files smaller than this threshold in megabytes are classified as
fragmented small files.
- id: fragmentation_ratio_threshold
type: FLOAT
defaults: 0.35
description: Partition fragmentation ratio (small files / total files) that
triggers automated compaction.
- id: snapshot_retention_days
type: INT
defaults: 7
description: Age in days past which historical Iceberg table snapshots are expired.
- id: table_identifier
type: STRING
defaults: analytics.events_lakehouse
description: Target Iceberg table identifier (catalog.schema.table).
tasks:
- id: profile_partition_fragmentation
type: io.kestra.plugin.jdbc.duckdb.Query
description: Analyzes partition file size distributions in DuckDB to compute
small file ratios and detect degraded partitions.
fetchType: FETCH_ONE
sql: |
WITH raw_file_stats AS (
{% if inputs.seed_demo_data %}
-- Synthetic Lakehouse partition telemetry (Simulating streaming ingestion small-file accumulation)
SELECT '2026-10-01' AS partition_date, 52 AS total_files, 48 AS small_files, 260.5 AS total_size_mb, 2.4 AS avg_file_size_mb UNION ALL
SELECT '2026-10-02' AS partition_date, 70 AS total_files, 65 AS small_files, 380.0 AS total_size_mb, 2.8 AS avg_file_size_mb UNION ALL
SELECT '2026-10-03' AS partition_date, 20 AS total_files, 4 AS small_files, 890.0 AS total_size_mb, 85.0 AS avg_file_size_mb UNION ALL
SELECT '2026-10-04' AS partition_date, 25 AS total_files, 2 AS small_files, 1150.0 AS total_size_mb, 92.0 AS avg_file_size_mb
{% else %}
-- Real lakehouse metadata query from Iceberg $files metadata table
SELECT
partition.partition_date,
COUNT(*) AS total_files,
COUNT(CASE WHEN file_size_in_bytes < ({{ inputs.small_file_threshold_mb }} * 1024 * 1024) THEN 1 END) AS small_files,
ROUND(SUM(file_size_in_bytes) / (1024.0 * 1024.0), 2) AS total_size_mb,
ROUND(AVG(file_size_in_bytes) / (1024.0 * 1024.0), 2) AS avg_file_size_mb
FROM iceberg_catalog.{{ inputs.table_identifier }}."$files"
GROUP BY partition.partition_date
{% endif %}
),
partition_evaluations AS (
SELECT
partition_date,
total_files,
small_files,
total_size_mb,
avg_file_size_mb,
ROUND(CAST(small_files AS DOUBLE) / CAST(total_files AS DOUBLE), 4) AS fragmentation_ratio,
CASE
WHEN (CAST(small_files AS DOUBLE) / CAST(total_files AS DOUBLE)) >= {{ inputs.fragmentation_ratio_threshold }}
THEN 1
ELSE 0
END AS requires_compaction
FROM raw_file_stats
)
SELECT
COUNT(*) AS total_partitions,
SUM(total_files) AS total_lakehouse_files,
SUM(small_files) AS total_small_files,
SUM(requires_compaction) AS fragmented_partition_count,
ROUND(AVG(fragmentation_ratio), 4) AS avg_fragmentation_ratio,
ROUND(SUM(CASE WHEN requires_compaction = 1 THEN total_size_mb ELSE 0 END), 2) AS compactable_mb,
-- Projected query scan speedup factor after bin-packing small files into 128MB chunks
ROUND(CAST(SUM(CASE WHEN requires_compaction = 1 THEN total_files ELSE 0 END) AS DOUBLE) /
GREATEST(1.0, CAST(CEIL(SUM(CASE WHEN requires_compaction = 1 THEN total_size_mb ELSE 0 END) / 128.0) AS DOUBLE)), 2) AS projected_speedup_factor
FROM partition_evaluations;
- id: evaluate_compaction_verdict
type: io.kestra.plugin.core.flow.If
description: Evaluates whether fragmented partition count exceeds zero to
trigger automated bin-pack compaction.
condition: "{{
outputs.profile_partition_fragmentation.row.fragmented_partition_count > 0
}}"
then:
- id: execute_bin_pack_compaction
type: io.kestra.plugin.scripts.shell.Commands
description: Executes bin-packing file compaction across degraded partitions to
consolidate small files into 128MB targets.
containerImage: python:3.11-slim
commands:
- |
echo "Consolidating {{ outputs.profile_partition_fragmentation.row.total_small_files }} small files across {{ outputs.profile_partition_fragmentation.row.fragmented_partition_count }} fragmented partitions..."
python3 -c "
small_files = {{ outputs.profile_partition_fragmentation.row.total_small_files }}
target_chunks = max(1, int({{ outputs.profile_partition_fragmentation.row.compactable_mb }} / 128.0))
print(f'Successfully compacted {small_files} small files into {target_chunks} optimized 128MB Parquet chunks.')
"
- id: expire_historical_snapshots
type: io.kestra.plugin.scripts.shell.Commands
description: Vacuums unreferenced historical metadata snapshots older than
configured retention days.
containerImage: python:3.11-slim
commands:
- |
echo "Expiring table snapshots older than {{ inputs.snapshot_retention_days }} days on {{ inputs.table_identifier }}..."
echo "Metadata vacuum complete: Reclaimed unreferenced manifest lists and metadata pointers."
- id: notify_lakehouse_health_card
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
description: Dispatches high-impact Lakehouse compaction summary card to Slack.
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"text": "❄️ *Apache Iceberg Lakehouse Compaction Complete*\n• *Target Table:* `{{ inputs.table_identifier }}`\n• *Partitions Compacted:* {{ outputs.profile_partition_fragmentation.row.fragmented_partition_count }} of {{ outputs.profile_partition_fragmentation.row.total_partitions }}\n• *Small Files Eliminated:* {{ outputs.profile_partition_fragmentation.row.total_small_files }} (< {{ inputs.small_file_threshold_mb }}MB)\n• *Volume Consolidated:* {{ outputs.profile_partition_fragmentation.row.compactable_mb }} MB\n• *Projected Query Scan Speedup:* {{ outputs.profile_partition_fragmentation.row.projected_speedup_factor }}x\n• *Snapshot Retention:* Purged history older than {{ inputs.snapshot_retention_days }} days."
}
else:
- id: log_optimal_partition_state
type: io.kestra.plugin.core.log.Log
description: Records optimal partition state when fragmentation ratio is below
the trigger threshold.
message: "Iceberg table {{ inputs.table_identifier }} is optimal (Average
Fragmentation: {{
outputs.profile_partition_fragmentation.row.avg_fragmentation_ratio
}}). No compaction needed."
triggers:
- id: scheduled_weekly_maintenance
type: io.kestra.plugin.core.trigger.Schedule
description: Weekly scheduled off-peak Lakehouse maintenance sweep. Shipped
disabled by default.
cron: "0 2 * * 0"
disabled: true
- id: lakehouse_maintenance_webhook
type: io.kestra.plugin.core.trigger.Webhook
description: Authenticated webhook for event-driven CDC batch compaction triggers.
key: "{{ secret('LAKEHOUSE_WEBHOOK_KEY') }}"
errors:
- id: alert_maintenance_failure
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
description: Alerts data engineering on-call if compaction maintenance fails.
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"text": "🚨 Iceberg Lakehouse Maintenance failed on execution {{ execution.id }} for table {{ inputs.table_identifier }}."
}