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

Forecast GCP Spend Against Your Budget Before the Invoice

Project end-of-month GCP spend from the BigQuery billing export, compare the forecast against your budget, and alert Slack before the invoice lands.

Categories
BusinessCloud

A budget alert that fires at 90% of the budget has already lost the argument: by then the money is mostly spent. This blueprint moves the decision earlier by forecasting instead of measuring. It queries the BigQuery billing export for month-to-date cost and the trailing 7-day cost, extends that recent pace across the remaining days of the month, and compares the projection against a budget input — over it, Slack gets the forecast, the headroom, and the service driving the spend while the month is still young enough to do something about it.

How it works

  1. fetch_spend_summary (io.kestra.plugin.gcp.bigquery.Query, FETCH_ONE) reads the standard daily billing export in a single pass: month-to-date cost, cost over the trailing 7 days, how many of those days actually have data, and the calendar facts (days_elapsed, days_in_month) the projection needs.
  2. fetch_top_service (io.kestra.plugin.gcp.bigquery.Query) ranks services by month-to-date cost and returns the leader, so the alert names where to cut rather than only how much is at stake.
  3. assess_forecast (io.kestra.plugin.scripts.python.Script on the io.kestra.plugin.core.runner.Process runner) extends the trailing 7-day daily pace across the remaining days of the month — a recent-pace forecast that reacts to a spike the same week it starts. When the recent window has no rows (a brand-new export), it falls back to a linear month-to-date projection, and it computes percent-of-budget and headroom either way.
  4. check_forecast (io.kestra.plugin.core.flow.If) compares projected_cost with the monthly_budget_usd input. Over it, alert_overspend posts the projection, budget, month-to-date numbers, forecast basis, and top service to Slack; under it, log_on_track keeps a quiet record so the execution history shows the month's runway.
  5. The errors block alerts Slack when the guard itself fails, and a daily Schedule trigger (shipped disabled) drives the cadence once enabled.

What you get

  • A projection, not a rear-view number: end-of-month cost estimated from this month's own recent pace.
  • A budget comparison with explicit headroom, so the question "how much room is left?" has a daily answer.
  • Per-service attribution in the alert, pointing at the largest line item before anyone opens the console.
  • A forecast_summary JSON output (month-to-date, projection, budget, percentages, basis, top service) for dashboards or downstream flows.

Who it's for

  • FinOps engineers who own a GCP budget and want to know where the month is heading, not where it has been.
  • Platform teams whose alarm at 80% of a budget always arrives too late to react.
  • Engineering leaders who have been surprised by a GCP invoice at least once.

Why orchestrate this with Kestra

The billing export already stores every cost row; what it cannot do is turn those rows into a scheduled decision. Kestra adds the loop: a daily schedule timed after the export lands, two BigQuery queries with retries, a Python projection step that needs no infrastructure of its own thanks to the Process runner, a branch that separates alerting from quiet record-keeping, and an execution history that doubles as a daily audit of the forecast. A cron script would run, but it would not retry, alert on its own failure, or leave a queryable trail.

Prerequisites

  • The standard daily BigQuery billing export enabled for your billing account, writing into the table named by billing_export_table.
  • A GCP service account that can run BigQuery jobs against the export dataset (for example roles/bigquery.jobUser plus a viewer role on the dataset).
  • Export data can lag by up to a day or two; the trailing-pace basis absorbs short gaps, but the first days of a brand-new export fall back to the linear projection.
  • A Slack incoming webhook for forecast and failure alerts.

Secrets

  • GCP_PROJECT_ID: project in which the BigQuery queries run.
  • GCP_SERVICE_ACCOUNT: service account key JSON with BigQuery job permissions.
  • SLACK_WEBHOOK_URL: Slack incoming webhook URL for overspend and failure alerts.

Quick start

  1. Add the three secrets to your Kestra namespace.
  2. Set billing_export_table to your export table's fully qualified name and monthly_budget_usd to your real budget.
  3. Execute the flow once and read forecast_summary (and the logs) to see your projection.
  4. Set disabled: false on the daily_forecast_check trigger.

How to extend

  • Add a second If that alerts on pct_used alone (for example 80% consumed) so slow and steady creep trips the guard even when the projection is still calm.
  • Group by project.id instead of service.description to attribute spend to the team whose project is growing.
  • Compare the projection against last month's actual spend (as the AWS blueprint in this repository does) for a month-over-month anomaly angle alongside the budget angle.
  • Fan the alert out to PagerDuty or a FinOps channel by adding another notification task in the then branch.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.