Query icon
OutputValues icon
Return icon
Switch icon
Log icon
SlackIncomingWebhook icon
Schedule icon

Cloud Tasks Queue Backlog and Failure Gate

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.

Categories
CloudInfrastructure

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.

How it works

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. log_audit_summary always runs last and logs the final classification.
  6. The errors block posts to Slack if the flow itself fails outside the gate logic above.

What you get

  • A real distinction between a queue that is backlogged and one whose dispatches are failing, from the same two Cloud Monitoring metrics Google itself documents for this purpose.
  • A Slack alert carrying the exact queue/depth and task_attempt_count values that triggered it, never an invented number.
  • A choice of which signal matters for a given queue (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.

Who it's for

  • Backend and platform teams running Cloud Tasks queues who need to know the difference between "the producer is outrunning the consumer" and "the consumer is down", not just that the queue looks unhealthy.
  • Teams evaluating the GCP Monitoring plugin who want a working example of 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.

Why orchestrate this with Kestra

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.

Prerequisites

  • A Cloud Tasks queue and a GCP service account with monitoring.timeSeries.list permission (roles/monitoring.viewer is enough, this blueprint only reads).
  • A Slack incoming webhook for alerts.
  • This plugin calls the Cloud Monitoring API directly from the Kestra worker process, there is no sub-container 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.

Secrets

  • 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.

Inputs

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

  • {{ 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).

Quick start

  1. Add the GCP and Slack secrets.
  2. Set queue_id and location to a real queue and run this flow manually.
  3. Read log_audit_summary for the real depth and failed-attempt numbers.
  4. Enable the every_ten_minutes trigger, whose cron matches the default window.

How to extend

  • Split 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.
  • Read cloudtasks.googleapis.com/queue/task_attempt_delays, a distribution metric, to alert on growing dispatch latency even before attempts start failing outright.
  • Add a second pair of probes for a second queue and reuse the same classification logic to monitor several queues from one flow.

Pitfalls

  • 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.
  • Cloud Monitoring can return zero time series for a metric when there has been no activity at all in the window, this blueprint treats that as 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.
  • This blueprint never pauses, purges, or redirects the queue, there is no remediation task in this flow, it is alert-only by design, Cloud Tasks queue management belongs in the service that owns the queue's configuration.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.