Schedule icon
Webhook icon
Query icon
Script icon
Process icon
If icon
SlackIncomingWebhook icon
Loop icon
Log icon

Snowflake Warehouse Credit Rightsizing with Dry-Run Gate

Join warehouse metering against query history, report warehouses burning credits with zero queries to Slack, and suspend them via allowlist-gated dry-run.

Categories
Cloud

How it works

  1. nightly_rightsizing (Schedule, shipped disabled) or on_demand_scan (event-based Webhook) starts the sweep.
  2. Two jdbc.snowflake.Query tasks pull Account Usage in parallel with the same lookback input: fetch_warehouse_usage aggregates warehouse_metering_history into credits_used per warehouse, and fetch_query_activity counts queries and distinct users per warehouse from query_history. Both use fetchType: FETCH and the row shape outputs.<task>.rows.
  3. analyze_rightsizing (scripts.python.Script, Process runner) joins the two result sets through Kestra's ::json:: outputs protocol: warehouses with zero queries over the window whose credit burn is at or above min_credits_to_act become suspend candidates; warehouses on exempt_warehouses are never candidates (matched case-insensitively); active warehouses and sub-threshold idlers are reported with verdicts. Every warehouse name is sanitized against ^[A-Za-z0-9_$]+$ before it can reach an ALTER statement, and the task emits candidates, checked_count, a full table, and a report_markdown grid - read back via outputs.<task>.vars.<field>.
  4. action_gate (If candidate_count > 0) always posts the report to Slack via messageText, then execute_gate (second If inputs.dry_run == false) decides: in dry-run (the default) it logs how many candidates were reported and touches nothing; otherwise suspend_warehouses (core.flow.Loop, concurrencyLimit: 1) walks the candidates serially and runs ALTER WAREHOUSE "name" SUSPEND per warehouse with fetchType: NONE. Zero-candidate runs take the else branch and log the clean sweep. announce_summary always closes with checked/candidate/dry-run counts.
  5. Outputs expose checked_count, candidate_count, candidates, usage_table, report_markdown, and dry_run; errors posts to Slack with wording that an errored sweep must not be read as "no idle burn".

What you get

  • Nightly visibility into which warehouses are burning credits with zero queries - the classic forgotten-warehouse leak.
  • A report-only default (dry_run: true) so the first runs are pure observability; flipping one input starts the suspensions.
  • An exemption list for warehouses that must stay warm (DR, month-end reporting) that no automation can touch.
  • Safe DDL: sanitized names, serial execution, and an errors alert that keeps Account Usage outages distinct from clean sweeps.

Who it's for

FinOps owners and Snowflake platform teams watching credit burn, and anyone who has ever found a 24/7 warehouse that nobody had queried in a month.

Why orchestrate this with Kestra

The findings live in two Account Usage views that have to be joined, alerted, approved-or-not, and re-run on a schedule - exactly the shape of work that rots as a notebook or a cron box. Kestra schedules the sweep, keeps the Slack report and the DDL in one execution history, and makes the dry-run flag a first-class input your auditors can see.

Prerequisites

  • A Snowflake account with ACCOUNT_USAGE visibility and rights to run ALTER WAREHOUSE.
  • Warehouse metering and query history retained for the chosen lookback window.
  • A Slack incoming webhook.

Secrets

  • SNOWFLAKE_JDBC_URL: JDBC connection URL, e.g. jdbc:snowflake://<account>.snowflakecomputing.com.
  • SNOWFLAKE_USER: Service user with ACCOUNT_USAGE read and warehouse-alter rights (the latter needed only when dry_run is false).
  • SNOWFLAKE_PASSWORD: Password for the service user.
  • SLACK_WEBHOOK_URL: Slack incoming webhook for sweep reports.

Quick start

  1. Set the four secrets and run with defaults: the sweep reports candidates in Slack and suspends nothing.
  2. Read candidates and report_markdown in the execution outputs; tune min_credits_to_act and exempt_warehouses to your estate.
  3. Re-run with dry_run: false when the list looks right - each candidate is suspended serially and the summary confirms it.
  4. Enable nightly_rightsizing so the sweep runs while the team sleeps.

How to extend

  • Add a second action tier: resume (not suspend) warehouses with query_count > 0 but suspiciously large sizes, using ALTER WAREHOUSE ... RESUME after a HumanTask approval.
  • Write usage_table to a Snowflake table for month-over-month rightsizing trends.
  • Pair with snowflake-cost-anomaly-detector (spend spikes) for a full FinOps loop: spikes from running warehouses, idle burn from stopped ones.
  • Escalate to a github.issues.Create ticket when a candidate survives three consecutive sweeps.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.