New to Kestra?
Use blueprints to kickstart your first workflows.
Audit Cloud Tasks queue backlog and dispatch failures on a schedule using real Cloud Monitoring metrics and alert Slack before a handler outage goes unnoticed.
A Cloud Tasks queue backs up for one of two reasons: the handler it dispatches to is down
or too slow, so task_attempt_count fills up with non-ok response codes, or the handler
is fine and the producer side is simply creating tasks faster than they can be drained, so
queue/depth climbs with a mostly-ok attempt history. The two causes need different
responses and look identical from a glance at the queue. This blueprint reads both real
Cloud Monitoring metrics, classifies what it actually finds, and alerts Slack with the
exact depth and failure numbers instead of a single ambiguous "queue is big" signal.
probe_queue_depth and probe_failed_attempts
(io.kestra.plugin.gcp.monitoring.Query) each query one cloudtasks.googleapis.com
metric scoped to queue_id and location over window, with allowFailure: true so
a credentials or project problem does not stop the flow before it can be classified as
PROBE_FAILED below.probe_queue_depth reads the queue/depth gauge metric, the number of tasks
currently in the queue.probe_failed_attempts reads the queue/task_attempt_count delta metric, filtered to
response_code!="ok", so only failed dispatch attempts count.extract_metric_values (io.kestra.plugin.core.output.OutputValues) pulls the real
number out of each query's raw Cloud Monitoring JSON: the most recent point's
value.int64Value for queue_depth, and the sum of every matching point's
value.int64Value for failed_attempts (a delta metric needs summing across the
window, a gauge only needs its latest point). Both default to 0 if the matching
probe produced output but found no time series at all, which Cloud Monitoring returns
for a genuinely empty or healthy queue, not an error.classify_queue_health (io.kestra.plugin.core.debug.Return) returns PROBE_FAILED
when either probe produced no output at all (guarded with is not defined),
CRITICAL when the signal selected by alert_on meets its own threshold, HEALTHY
otherwise.route_by_queue_health (io.kestra.plugin.core.flow.Switch) branches on that status:
HEALTHY logs the real depth and failure numbers, CRITICAL and PROBE_FAILED each
alert Slack with those same real numbers, never an invented count.log_audit_summary always runs last and logs the final classification.errors block posts to Slack if the flow itself fails outside the gate logic above.queue/depth and task_attempt_count values that
triggered it, never an invented number.alert_on), a queue with a bursty
producer may only care about depth, one calling a flaky downstream handler may only
care about failed attempts.gcp.monitoring.Query against a real Google Cloud metric namespace with resource and
metric label filters, including how to extract a value out of the raw time series JSON.Cloud Monitoring can fire a native alerting policy, but turning that into a message that says "which queue, how deep, how many failures, over what window" without also wiring an additional notification channel is its own project. Kestra adds the schedule, the single declarative query against both metrics, the classification that extracts the real numbers out of the raw time series response, and a Slack alert built from them, all as one YAML file you can version and review like code next to the rest of your data pipelines.
monitoring.timeSeries.list permission (roles/monitoring.viewer is enough, this
blueprint only reads).taskRunner and no Docker network to join, any machine
Kestra runs on that can reach the Google Cloud Monitoring API works. Cloud Tasks and
Cloud Monitoring are both managed Google Cloud services with no self-hostable
open-source emulator for either.GCP_SERVICE_ACCOUNT, GCP_PROJECT_ID: used by both io.kestra.plugin.gcp.monitoring.Query tasks.
SLACK_WEBHOOK: Slack incoming webhook URL used by the alert tasks and the errors
block.
In Kestra OSS, set all three as base64-encoded environment variables:
SECRET_GCP_SERVICE_ACCOUNT, SECRET_GCP_PROJECT_ID, SECRET_SLACK_WEBHOOK.
| Input | Type | Default | Allowed values |
|---|---|---|---|
queue_id |
STRING | default-queue |
any Cloud Tasks queue ID |
location |
STRING | us-central1 |
any GCP region running Cloud Tasks |
window |
STRING | PT10M |
any ISO-8601 duration |
queue_depth_critical_threshold |
INT | 1000 |
any non-negative integer |
failed_attempt_critical_threshold |
INT | 10 |
any non-negative integer |
alert_on |
SELECT | both |
depth, failures, both |
{{ outputs.extract_metric_values.values.queue_depth }}: most recent queue depth count (0 if no time series returned).{{ outputs.extract_metric_values.values.failed_attempts }}: sum of non-ok task attempt failures across window (0 if no time series returned).{{ outputs.classify_queue_health.value }}: health classification (HEALTHY, CRITICAL, or PROBE_FAILED).queue_id and location to a real queue and run this flow manually.log_audit_summary for the real depth and failed-attempt numbers.every_ten_minutes trigger, whose cron matches the default window.probe_failed_attempts into one query per specific non-ok response_code (for
example UNAVAILABLE versus DEADLINE_EXCEEDED) to tell a slow handler apart from a
down one in the alert text.cloudtasks.googleapis.com/queue/task_attempt_delays, a distribution metric, to
alert on growing dispatch latency even before attempts start failing outright.queue/depth is a gauge, read its latest point. task_attempt_count is a delta, sum
every point across the window, reading only its latest point badly undercounts failures
that happened earlier in the window.0, a healthy empty
result, not a reason to alert, confirm that matches your expectations for a queue that
is sometimes genuinely idle.resource.labels.queue_id and resource.labels.location must match exactly, a typo in
either silently returns zero time series rather than an error, which this gate reports
as HEALTHY with depth=0, not PROBE_FAILED.