New to Kestra?
Use blueprints to kickstart your first workflows.
Monitor Step Functions execution failures via CloudWatch's own metrics and alert Slack before a failing workflow goes unnoticed.
A Step Functions state machine that starts failing every execution -
a broken downstream integration, an expired credential inside a Task
state, a Lambda that started throwing - has no first-class "alert me"
primitive of its own; CloudWatch alarms have to be configured and
wired separately for every state machine. This blueprint reads the
same ExecutionsFailed metric CloudWatch alarms would use, classifies
it, and alerts Slack directly from a Kestra flow instead.
periodic_failure_check (io.kestra.plugin.core.trigger.Schedule) runs every 15 minutes, explicitly passing aws_region, state_machine_arn, query_window_minutes, and max_failed_executions through its own inputs: block so the flow is self-contained when the trigger fires. Shipped disabled so a manual run can be verified first.probe_failed_executions (io.kestra.plugin.aws.cloudwatch.Query) queries the AWS/States namespace's ExecutionsFailed metric, scoped to state_machine_arn via the StateMachineArn dimension, with periodSeconds set to the full lookback window so CloudWatch returns a single aggregated Sum datapoint rather than one per minute.evaluate_metric_presence (io.kestra.plugin.core.flow.If) branches on whether any datapoint came back at all (count).then (NO_DATA): log_no_metric_data reports that no executions ran in this window at all.else: nested evaluate_failure_threshold (io.kestra.plugin.core.flow.If) branches on whether the aggregated Sum exceeds max_failed_executions.then (FAILURES_DETECTED): alert_failures_detected reports the count to Slack.else (HEALTHY): log_executions_healthy records a clean check.log_audit_complete always runs last, printing the datapoint count regardless of which branch fired.errors block alerts Slack separately if the flow itself fails outright - an unreachable CloudWatch API or bad credentials must not read as any of the three handled states.io.kestra.plugin.aws.cloudwatch.Query with periodSeconds deliberately set equal to the full lookback window, so the flow reads one pre-aggregated Sum value instead of summing several datapoints itself in Pebble.cloudwatch:GetMetricStatistics only) that cannot touch Step Functions executions at all, by construction.Query scoped to a specific resource via a dimension, with the statistic deliberately chosen to match AWS's own documented guidance for count-type metrics.CloudWatch alarms can notify on a threshold, but configuring one per state machine, wiring it to SNS, and keeping that configuration in sync with the state machines that actually exist is its own maintenance burden, separate from the flow that needs to react. Kestra supplies the schedule, the NO_DATA/HEALTHY/FAILURES_DETECTED classification as a first-class branch, and an execution history that shows exactly when a state machine started failing and how many executions were affected.
aws_region, state_machine_arn).cloudwatch:GetMetricStatistics permission - nothing from Step Functions itself is required, since this blueprint never calls the Step Functions API.This blueprint has no local, account-free testing path. LocalStack's Community image now requires its own account and auth token as of March 2026 (it is no longer a plain, no-signup Docker image), and even where available, LocalStack's CloudWatch metrics support is limited. A real AWS account is the practical prerequisite here, the same baseline every other AWS-targeting blueprint in this repository assumes.
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY: credentials for io.kestra.plugin.aws.cloudwatch.Query.SLACK_WEBHOOK_URL: Slack incoming webhook used by alert_failures_detected and the errors block.SECRET_, base64-encoded - for example SECRET_SLACK_WEBHOOK_URL=$(echo -n '<your-webhook-url>' | base64) - and read back in flows with {{ secret('NAME') }}.aws_region (STRING, default us-east-1).state_machine_arn (STRING, default <your-state-machine-arn>, must be replaced).query_window_minutes (INT, default 15): drives both window and periodSeconds on the probe task.max_failed_executions (INT, default 0): failure-count ceiling before FAILURES_DETECTED fires.outputs.probe_failed_executions.count: number of datapoints returned (expected 0 or 1, since periodSeconds equals the full window).outputs.probe_failed_executions.series[0].sum: the aggregated failed-execution count for the window, only present when count is 1 (supports sum or Sum).AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and SLACK_WEBHOOK_URL secrets.log_executions_healthy or log_no_metric_data fires, depending on recent execution volume.query_window_minutes to confirm alert_failures_detected fires.periodic_failure_check once you trust the check against your real state machine.state_machine_arn values with io.kestra.plugin.core.flow.Loop to audit every critical state machine in an account in one run.io.kestra.plugin.aws.cloudwatch.Query probe on ExecutionsTimedOut (also documented under the same AWS/States namespace) to catch stuck-and-timing-out executions as a distinct state from outright failures.OpenExecutionCount metric (dimensionless, no StateMachineArn needed) to additionally catch a state machine approaching its open-execution quota before any individual execution fails.NO_DATA is not a perfectly reliable signal that zero executions actually failed, only that CloudWatch has not reported any yet.Sum statistic for count-type metrics like ExecutionsFailed, not the task's own default of Average - this blueprint sets statistic: "Sum" explicitly for exactly that reason; leaving it at the default would silently report an averaged value instead of a true count.periodSeconds must be kept in sync with window. Both are derived from the single query_window_minutes input specifically so they cannot drift apart; setting them independently risks CloudWatch returning multiple smaller datapoints that this flow's single series[0] read would then silently ignore all but the first of.ExecutionsFailed metric, the AWS/States namespace, the StateMachineArn dimension, and the Sum-statistic recommendation are all taken verbatim from AWS's own Step Functions CloudWatch monitoring documentation, and the io.kestra.plugin.aws.cloudwatch.Query properties and outputs are taken from the plugin's own source on main - but no Kestra engine was run to execute this flow end to end.