在Step Functions中执行SSM命令后如何正确捕获结果并判定状态?
解决Step Functions无法捕获SSM命令执行结果的问题
问题根源在于你当前使用的ssm:sendCommand仅负责提交命令请求,只要AWS成功接收请求就会标记任务为成功,完全不会跟踪后续EC2实例上的命令执行状态。要实现根据实际执行结果判定任务成败,需要额外步骤来查询或监听命令的最终状态。
方案一:轮询查询命令执行状态(简单易实现)
通过添加状态机步骤,主动轮询SSM命令的执行结果,根据结果分支处理成功/失败:
完整状态机定义
{ "Comment": "Copy File to S3 State Machine with Command Result Check", "StartAt": "SendCommand", "States": { "SendCommand": { "Type": "Task", "Resource": "arn:aws:states:::aws-sdk:ssm:sendCommand", "Parameters": { "DocumentName": "AWS-RunShellScript", "Parameters": { "commands": [ "sudo -u muser aws s3 mv s3://dev-etl/shared-data/temp1/ s3://dev-etl/temp/ --recursive --exclude '*' --include 'abc.sql' " ] }, "Targets": [ { "Key": "InstanceIds", "Values": [ "i-sampleinstanceid" ] } ] }, "Next": "WaitForCommandInitialExecution" }, "WaitForCommandInitialExecution": { "Type": "Wait", "Seconds": 10, "Next": "GetCommandExecutionResult" }, "GetCommandExecutionResult": { "Type": "Task", "Resource": "arn:aws:states:::aws-sdk:ssm:getCommandInvocation", "Parameters": { "CommandId.$": "$.Command.CommandId", "InstanceId.$": "$.Command.InstanceIds[0]" }, "Retry": [ { "ErrorEquals": ["States.ALL"], "IntervalSeconds": 10, "MaxAttempts": 5, "BackoffRate": 2.0 } ], "Next": "CheckCommandResult" }, "CheckCommandResult": { "Type": "Choice", "Choices": [ { "Variable": "$.Status", "StringEquals": "Success", "Next": "CommandSucceeded" }, { "Variable": "$.Status", "StringEquals": "Failed", "Next": "CommandFailed" }, { "Variable": "$.Status", "StringEquals": "TimedOut", "Next": "CommandFailed" } ], "Default": "CommandFailed" }, "CommandSucceeded": { "Type": "Succeed" }, "CommandFailed": { "Type": "Fail", "Error": "SSMCommandExecutionFailed", "Cause.$": "$.StatusDetails" } } }
关键说明
SendCommand:提交命令后,保存返回的CommandId和目标实例ID,用于后续查询WaitForCommandInitialExecution:等待10秒,避免命令还未开始执行就查询(可根据实际命令执行时长调整)GetCommandExecutionResult:调用ssm:getCommandInvocation查询命令执行状态,配置重试逻辑处理命令仍在运行的情况CheckCommandResult:根据返回的Status字段判断结果,分支到成功或失败状态
方案二:使用EventBridge事件触发(异步高效)
通过配置SSM命令执行完成后发送EventBridge事件,由Lambda回调Step Functions任务令牌,避免轮询:
步骤1:修改状态机为异步等待模式
{ "Comment": "Copy File to S3 State Machine with EventBridge Callback", "StartAt": "SendCommandWithCallback", "States": { "SendCommandWithCallback": { "Type": "Task", "Resource": "arn:aws:states:::aws-sdk:ssm:sendCommand", "Parameters": { "DocumentName": "AWS-RunShellScript", "Parameters": { "commands": [ "sudo -u muser aws s3 mv s3://dev-etl/shared-data/temp1/ s3://dev-etl/temp/ --recursive --exclude '*' --include 'abc.sql' " ] }, "Targets": [ { "Key": "InstanceIds", "Values": [ "i-sampleinstanceid" ] } ], "NotificationConfig": { "NotificationArn": "arn:aws:events:YOUR_REGION:YOUR_ACCOUNT_ID:event-bus/default", "NotificationEvents": ["Success", "Failed", "TimedOut"], "NotificationType": "Command" }, "Comment.$": "States.Format('TaskToken: {}', $$.Task.Token)" }, "Next": "WaitForCommandCompletion" }, "WaitForCommandCompletion": { "Type": "Wait", "ForTaskToken": true } } }
步骤2:配置Lambda回调函数
创建Python Lambda函数,解析EventBridge事件并回调Step Functions:
import boto3 import re stepfunctions = boto3.client('stepfunctions') def lambda_handler(event, context): # 从事件中提取命令状态和任务令牌 detail = event['detail'] status = detail['status'] comment = detail['comment'] # 从Comment中匹配TaskToken token_match = re.search(r'TaskToken: (\S+)', comment) if not token_match: return {"message": "Task token not found in comment"} task_token = token_match.group(1) if status == "Success": # 通知Step Functions任务成功 stepfunctions.send_task_success( taskToken=task_token, output=f'{{"status": "Success", "command_details": {str(detail)}}}' ) else: # 通知Step Functions任务失败 stepfunctions.send_task_failure( taskToken=task_token, error="SSMCommandFailed", cause=f"Command failed with status: {status}. Details: {str(detail)}" ) return {"message": "Callback sent successfully"}
步骤3:配置EventBridge规则
- 事件源:
aws.ssm - 事件类型:
EC2 Command Invocation State Change - 目标:上述Lambda函数
- 可选:添加过滤条件,仅针对目标实例或特定CommandId的事件
权限注意事项
- 方案一:Step Functions执行角色需要
ssm:GetCommandInvocation权限 - 方案二:SSM需要有向EventBridge发送事件的权限;Lambda执行角色需要
states:SendTaskSuccess和states:SendTaskFailure权限
内容的提问来源于stack exchange,提问作者Amaravathi Satya
相关产品推荐
相关产品推荐

