You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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"
    }
  }
}

关键说明

  1. SendCommand:提交命令后,保存返回的CommandId和目标实例ID,用于后续查询
  2. WaitForCommandInitialExecution:等待10秒,避免命令还未开始执行就查询(可根据实际命令执行时长调整)
  3. GetCommandExecutionResult:调用ssm:getCommandInvocation查询命令执行状态,配置重试逻辑处理命令仍在运行的情况
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:27:55