我有一个对象数组,我想将其迭代传递给 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
}
}
}
我没有使用集成的 AWS 服务(即 AWS Step Function),而是使用 JavaScript 的
aws-sdk
v3 创建了自己的脚本来启动 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
}
}
ecs:runTask 可以通过两种不同的方式触发。
这种情况我们需要使用第二种方法,
将 TASK_TOKEN 作为环境变量传递给 ECS 任务,在 ECS 任务的前几行代码中,我们需要发送 SendTaskSucess。
这是一个例子:
{
"StartAt":"Run",
"States":{
"Run":{
"End":true,
"Type":"Task",
"Resource":"arn:aws:states:::ecs:runTask.waitForTaskToken",
"Parameters":{
"Cluster":"arn:aws:ecs:us-east-1:620018741331:cluster/HelloCdkStack-ecstaskEc2ClusterB0EAAA1E-yPWjSYf8d03O",
"TaskDefinition":"HelloCdkStackecstaskTD1950FF01",
"Overrides":{
"ContainerOverrides":[
{
"Name":"TheContainer",
"Environment":[
{
"Name":"TASK_TOKEN",
"Value.$":"$$.Task.Token"
}
]
}
]
},
"LaunchType":"EC2"
}
}
}
}
AWS CLI 有一个方便的
aws ecs wait tasks-running
命令。一些 AWS 开发工具包提供类似的操作。此命令的文档指出:
等到使用
轮询时,JMESPath 查询tasks[].lastStatus 对所有元素返回 RUNNING。它将每 6 秒轮询一次,直到达到成功状态。在 100 次失败检查后,这将退出并返回代码 255describe-tasks
换句话说,“等待”操作只是构建在 ECSDescribeTasks API 操作之上的简单轮询行为。
您可以在 AWS Step Function 中本地实现相同的轮询行为。 等待状态,然后是AWS SDK集成状态以调用ECSDescribeTasks操作,然后是选择状态以评估
lastStatus
值并继续到适当的下一个状态(例如“正在运行”、“失败”) ”,或返回等待状态。)
可视化 Workflow Studio 设计器使定义这种轮询模式变得非常容易。本机 Step Function 解决方案的一个潜在好处是需要管理的 AWS 资源更少(您无需定义 Lambda 函数来实施轮询)。一个潜在的缺点是成本。当前标准工作流程的AWS Step Function 定价基于状态转换,因此这种方法可能会很昂贵(取决于数量),因为每个轮询循环都涉及“等待”、“描述”和“选择”状态的转换。如果您的工作流程运行时间不超过 5 分钟,那么快速工作流程可能是更好的选择。