I have an array of objects which I want to pass to a Lambda function iteratively. However, I also need to have an ECS Task running for each Lambda function I start.
I found that I would need to have an AWS Step Function where I iterate through an array of JSON inputs. For each input, I would have to start an ECS Task, wait for it to be in a RUNNING state, then move to next step where I invoke a Lambda function. In my case, the ECS Task itself does not return anything. It is supposed to stay running because the Lambda function uses it.
Currently, I have it so that the ECS Task starts but it stays stuck in the starting the ECS Task step because it does not return anything. How would I be able to wait for it be in a RUNNING state before moving to the next step?
Current Step Function definition:
{
"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 can be triggered in two different ways.
We need to use second method in this case,
Pass TASK_TOKEN as environment variable to ECS task and within ECS task first few lines of code, we need to send a SendTaskSucess.
Here is an example:
{
"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"
}
}
}
}
Instead of using an integrated AWS service (ie AWS Step Function), I created my own script for starting ECS Tasks using aws-sdk
v3 for JavaScript. I specifically used the waitUntilTasksRunning
function from the @aws-sdk/client-ecs
package to wait for the ECS Task to be in a RUNNING state.
Read more about it from the documentation
Sample function for running and waiting for the ECS Task to be in a RUNNING state (TypeScript) note: not all parameters in the functions are required, check the documentation for that:
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
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.