在转到 AWS Step Function 的下一步之前,如何等待 AWS ECS 任务处于 RUNNING 状态?

问题描述

我有一个对象数组,我想以迭代方式将其传递给 Lambda 函数。但是,我还需要为我启动的每个 Lambda 函数运行一个 ECS 任务。

我发现我需要一个 AWS Step Function 来遍历 JSON 输入数组。对于每个输入,我必须启动一个 ECS 任务,等待它处于 RUNNING 状态,然后转到调用 Lambda 函数的下一步。就我而言,ECS 任务本身不返回任何内容。它应该保持运行,因为 Lambda 函数使用它。

目前,我有它以便 ECS 任务启动,但它停留在启动 ECS 任务步骤中,因为它没有返回任何内容。在进入下一步之前,我如何能够等待它处于 RUNNING 状态?

当前阶跃函数定义:

{
  "StartAt": "Iterate","States": {
    "Iterate": {
      "Type": "Map","Iterator": {
        "StartAt": "Start ECS Task","States": {
          "Start ECS Task": {
            "Type": "Task","Resource": "arn:aws:states:::ecs:runTask","Parameters": {
              "LaunchType": "FARGATE","Cluster": "<cluster-arn>","TaskDeFinition": "<task-deFinition-arn>","NetworkConfiguration": {
                "AwsvpcConfiguration": {
                  "subnets": [
                    "<subnet-id>"
                  ],"AssignPublicIp": "ENABLED"
                }
              }
            },"Next": "Invoke Lambda function"
          },"Invoke Lambda function": {
            "Type": "Task","Resource": "arn:aws:states:::lambda:invoke","Parameters": {
              "FunctionName": "<lambda-function-arn>","Payload": {
                "Input.$": "$"
              }
            },"End": true
          }
        }
      },"End": true
    }
  }
}

解决方法

ecs:runTask 可以通过两种不同的方式触发。

  • arn:aws:states:::ecs:runTask.sync > 运行并等待任务完成
  • arn:aws:states:::ecs:runTask.waitForTaskToken - 触发并等待它收到 SendTaskSucess or sendTaskFailure

在这种情况下我们需要使用第二种方法,

将 TASK_TOKEN 作为环境变量传递给 ECS 任务,在 ECS 任务的前几行代码中,我们需要发送一个 SendTaskSucess。

这是一个例子:

List<UUID> employeeUuidList = employeeService.findAllEmployeesByMainUuid(request.getMainUuid());
,

我没有使用集成的 AWS 服务(即 AWS Step Function),而是使用 aws-sdk v3 for JavaScript 创建了自己的脚本来启动 ECS 任务。我专门使用了 waitUntilTasksRunning 包中的 @aws-sdk/client-ecs 函数来等待 ECS 任务处于 RUNNING 状态。

从文档中阅读更多相关信息

运行和等待 ECS 任务处于 RUNNING 状态(TypeScript)的示例函数注意:并非函数中的所有参数都是必需的,请查看文档:

import { ECSClient,RunTaskCommand,waitUntilTasksRunning } from '@aws-sdk/client-ecs'

const startAndWaitUntilECSTaskRunning = async (region: string,clusterARN: string,launchType: string,subnets: Array<string>,taskDefinition: string,securityGroups: Array<string>,assignPublicIp: string) => {
    var ecsClient = new ECSClient({ "region": region })
    var runTaskCommand = new RunTaskCommand({
        cluster: clusterARN,taskDefinition: taskDefinition,launchType: launchType,networkConfiguration: {
            awsvpcConfiguration: {
                assignPublicIp: assignPublicIp,subnets: subnets,securityGroups: securityGroups
            }
        }
    })
    var ecsTask = await ecsClient.send(runTaskCommand)
    var taskArn: string | undefined = ecsTask.tasks?.[0].taskArn
    if (typeof taskArn !== "string") {
        throw Error("Task ARN is not defined.")
    }
    var waitECSTask = await waitUntilTasksRunning({"client": ecsClient,"maxWaitTime": 600,"maxDelay": 1,"minDelay": 1},{"cluster": clusterARN,"tasks": [taskArn]})
    // note: there are multiple waitECSTask states,check the documentation for more about that
    if (waitECSTask.state !== 'SUCCESS') {
        // your code to handle this
    } else {
        // your code to handle this
    }
}