Skip to main content
idle · gcp

Cloud Spanner instances billing node-hours with zero requests

resource types
1
rule IDs covered
1
severity
high

What does ZopNight detect here?

Cloud Spanner bills per node-hour whether or not queries arrive. ZopNight reads the SpannerRequestCount series for each instance and flags only those whose average and maximum both sit at 0 across the full window, treating the entire monthly bill as recoverable because an unqueried instance has no partial value.

Signal and threshold

How ZopNight evaluates Cloud Spanner instances billing node-hours with zero requests.
Field Value
Rule IDsRC-1243
Categoryidle
Severityhigh
Metricnone — pure configuration read
Sourcespanner_idle.go

Node-hours accrue without queries

Spanner is provisioned capacity: you pay per node-hour (or per processing unit) from the moment the instance exists, and the database keeps its regional replicas running whether applications query it or not. A Spanner instance is one of the more expensive things to forget: even a single-node regional instance runs to hundreds of dollars a month. That is why this rule carries high severity and a delete lever rather than a resize.

One metric, read by name

A Spanner instance surfaces 6 different monitoring series, so the rule never reads whichever metric happens to come first for the resource. It looks up SpannerRequestCount by its exact name and fires only when both the average and the maximum of the full harvested series are 0. Any measured request, however small, clears the instance. The read path is Cloud Monitoring’s monitoring.timeSeries.list permission, part of roles/monitoring.viewer.

The savings math is deliberately unclever: zero requests means 100% of the node-hours are waste, so the recoverable amount is the instance’s full monthly cost, and the optimized cost is $0.

Query the request count yourself

Terminal window
curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://monitoring.googleapis.com/v3/projects/PROJECT_ID/timeSeries?filter=metric.type%3D%22spanner.googleapis.com%2Fapi%2Fapi_request_count%22&interval.startTime=$(date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)&interval.endTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)"

An empty response over 30 days corroborates what the rule saw.

Before the delete

Export the data first; the Dataflow template “Cloud Spanner to Avro Files on Cloud Storage” is the standard route. Then delete the instance to stop the per-node charge. If the workload is real but bursty, the Spanner autoscaler is the middle path between always-on nodes and deletion.

Why some idle instances never surface

The rule abstains whenever pricing for the instance is unknown or zero, and whenever the SpannerRequestCount series is absent. There is intentionally no metadata fallback: request activity is a monitoring time series, not an asset-inventory field, so an uninstrumented instance produces no recommendation rather than a guessed one. A high-severity delete is only ever backed by measured data.

See it fire on your bill.

Connect an account read-only. The first findings land in minutes.

417 rule families across 353 resource types on 22 platforms. Every threshold, metric, and IAM action is documented on these pages before you grant anything.

417 rule families documented
353 resource types covered
read-only default access level
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·