Schedule icon
Consume icon
Return icon
Switch icon
Log icon
SlackIncomingWebhook icon

SQS Queue Depth Sentinel

Sample an Amazon SQS queue on a schedule without deleting messages and alert Slack when backlog crosses warning or critical thresholds.

Categories
CloudInfrastructure

An Amazon SQS backlog can build for minutes before anyone notices, since SQS itself has no built-in alerting on depth. This blueprint turns a scheduled, non-destructive sample into a Day 2 health gate: io.kestra.plugin.aws.sqs.Consume reads up to critical_queue_depth messages with autoDelete disabled, so nothing sampled here is ever permanently removed, classifies the count against two thresholds, and routes the result to a quiet log, an informational Slack note, or a Slack page depending on severity.

How it works

  1. probe_queue_depth (io.kestra.plugin.aws.sqs.Consume) polls queue_url in aws_region for up to probe_duration, stopping early at critical_queue_depth messages. autoDelete: false means every sampled message stays in the queue and simply becomes visible again to real consumers after sample_visibility_timeout seconds, instead of being deleted. allowFailure: true keeps a connection or permissions failure from aborting the flow outright.
  2. classify_queue_depth (io.kestra.plugin.core.debug.Return) evaluates a single Pebble expression against the sampled count: missing entirely becomes UNREACHABLE, at or above critical_queue_depth becomes CRITICAL, at or above warning_queue_depth becomes WARNING, otherwise HEALTHY.
  3. route_by_depth (io.kestra.plugin.core.flow.Switch) branches on that classification: HEALTHY logs a quiet confirmation; WARNING posts an informational Slack note; CRITICAL and UNREACHABLE each page Slack with the sampled count, the configured thresholds, and the execution id; a defaults fallback logs the raw value for any classification outside the four known cases.
  4. log_audit_result (io.kestra.plugin.core.log.Log) writes one audit line per run, independent of which Switch branch fired, so the check's own history stays queryable even if Slack delivery fails.
  5. The flow-level errors block pages Slack separately if the flow fails outright, so a broken sentinel is never mistaken for a quiet queue.
  6. The queue_depth_schedule trigger samples every 10 minutes and ships disabled: true, with explicit inputs: overrides for probe_duration and sample_visibility_timeout so the scheduled run's probe window is pinned regardless of this flow's own defaults.

What you get

  • A scheduled, non-destructive depth check for any SQS queue with zero custom polling code.
  • A single status output (HEALTHY / WARNING / CRITICAL / UNREACHABLE) other flows can gate on.
  • Three distinct Slack messages, one per severity, each carrying the sampled count and the threshold that tripped it.
  • An audit log line on every run, separate from Slack, so the check's own history survives a webhook outage.

Who it's for

  • Platform and backend teams running SQS-backed work queues who have no orchestrator-side depth alert today.
  • On-call engineers who want a backlog-building signal before consumers visibly fall behind or a downstream SLA is missed.
  • Teams standardizing Day 2 queue monitoring across mixed messaging systems inside Kestra without writing a bespoke CloudWatch alarm or polling script.

Why orchestrate this with Kestra

CloudWatch can alarm on ApproximateNumberOfMessagesVisible, but that lives outside your flow logic in a separate alarm resource with its own actions to wire up. Kestra keeps the whole check in one place: the schedule, the non-destructive sample, the threshold classification, and the Slack call are all one auditable execution history, with the Switch branch ready to grow into real remediation (fanning out more consumers, opening a ticket) without rewriting the check itself.

Prerequisites

  • An existing Amazon SQS queue reachable at queue_url.
  • AWS credentials with sqs:ReceiveMessage permission on that queue (and nothing else, since autoDelete: false never calls DeleteMessage).
  • A Slack incoming webhook for the WARNING, CRITICAL, UNREACHABLE, and flow-failure alerts.

Secrets

  • AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY: AWS credentials used to sample the queue.
  • SLACK_WEBHOOK_URL: Slack incoming webhook used for every alert branch and the flow-failure alert.

In Kestra OSS (no Enterprise secrets backend), secrets are supplied as environment variables prefixed SECRET_, base64-encoded, and read back in flows with {{ secret('NAME') }}, for example SECRET_SLACK_WEBHOOK_URL=$(echo -n 'https://hooks.slack.com/services/<placeholder>' | base64). This keeps credentials out of the flow YAML but, per Kestra's own documentation, offers no encryption at rest or access control beyond the host environment; use the Enterprise secrets backend for stronger guarantees.

Quick start

  1. Start a local LocalStack container to emulate SQS without a real AWS account, avoiding host port 8080 since Kestra's own UI already uses it: docker run -d --name localstack -p 4566:4566 localstack/localstack:latest
  2. If Kestra is also running in Docker, attach LocalStack to Kestra's network so the worker can reach it by container name: docker network connect YOUR_KESTRA_NETWORK localstack
  3. Create a test queue and send a few messages: docker exec localstack awslocal sqs create-queue --queue-name orders docker exec localstack awslocal sqs send-message --queue-url http://localhost:4566/000000000000/orders --message-body "test"
  4. Add AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY (LocalStack accepts any non-empty placeholder values, e.g. test/test) and SLACK_WEBHOOK_URL as secrets, set queue_url to the LocalStack queue URL, and run the flow once manually to confirm status reads HEALTHY.
  5. Enable queue_depth_schedule once pointed at a real queue.

How to extend

  • Point this flow at a real AWS account by setting queue_url/aws_region to a live queue; no code change is needed for the non-LocalStack path.
  • For a non-AWS, S3-compatible-style local endpoint instead of LocalStack's default routing, add an endpointOverride property to probe_queue_depth pointing at your emulator; leave it unset for real AWS rather than templating it to an empty string.
  • Add a third, lower info_queue_depth tier if you want a Slack note on any non-zero backlog, not just at the warning threshold.
  • Push status into a KV store and alert only on state transitions instead of every run.

Inputs

  • queue_url: full URL of the SQS queue to sample.
  • aws_region: AWS region the queue lives in.
  • probe_duration: ISO-8601 duration cap on how long the sampling task runs.
  • sample_visibility_timeout: seconds a sampled message stays hidden before returning to visibility.
  • warning_queue_depth: floor at or above which the queue is classified WARNING.
  • critical_queue_depth: floor at or above which the queue is classified CRITICAL, and the sampling task's maxRecords cap.

Outputs

  • status: one of HEALTHY, WARNING, CRITICAL, UNREACHABLE.

Links

Pitfalls

  • A sample is a point-in-time read, not SQS's own ApproximateNumberOfMessagesVisible attribute; under concurrent consumers or overlapping runs the sampled count can undercount the true backlog.
  • Setting warning_queue_depth or critical_queue_depth too low relative to real traffic produces false alerts; tune both against an observed healthy baseline before enabling the schedule.
  • autoDelete: false is what makes this check non-destructive; changing it to true turns this monitor into a consumer that permanently removes the messages it samples.
  • Keep sample_visibility_timeout short. A long timeout hides sampled messages from real consumers for that entire window even though they are never deleted.
  • Do not template endpointOverride to an empty string to "optionally" support LocalStack; only add the property when actually targeting a non-AWS endpoint.
See How

New to Kestra?

Use blueprints to kickstart your first workflows.