AWS Step Function Synchronous Task Token - amazon-web-services

I have a use case which I want to use Step Functions to solve but I can't find a way to solve this problem. Your help would be greatly appreciated.
The problem goes like this: I have an Amazon API Gateway which has a /start endpoint. a POST to this endpoint should start a data processing session and return a URL to an app which the API client can use to capture some data. Once data capture is complete, some processing takes place before the final response is sent to the API client via a callback.
My thinking, as you can see below, is to generate a task token and send it to the Data Capture Service. Then, when the user data capture is complete, the service can send a request to the Step Function API to say that stage is complete. The problem with this is how can I return the URL to the client from within the Step Function? I don't want to use a callback to do this.
One option is to create the data capture session within the 'Step Function Initiator' Lambda but then how do I provide the Data Capture Service with a task token?
Really, what I need is some mechanism of synchronously returning something (either a URL from that call or the task token from the first stage) from within the Step Function to the Lambda which started the execution. Is this possible? How would you solve this?

In step function initiator lambda, you must be doing start-execution which returns an executionArn
Next, you can loop and call get-execution-history api and task token will be part of the 'capture data' task parameters. Since this is the first step, this really should be done with in couple of seconds, so, we can keep running this loop every second until desired step in step function is initiated and task token can be obtained.
Take this example, i am passing the task token to another step function call from current step function.
{
"StartAt":"ChildTask",
"States":{
"ChildTask":{
"End":true,
"Type":"Task",
"Resource":"arn:aws:states:::states:startExecution.waitForTaskToken",
"Parameters":{
"Input":{
"token.$":"$$.Task.Token",
"foo":"bar"
},
"StateMachineArn":"arn:aws:states:us-east-1:110011001100:stateMachine:ChildStateMachine",
"Name":"MyExecutionName"
}
}
}
}
Get Execution history:
aws stepfunctions get-execution-history --execution-arn arn:aws:states:us-east-1:110011001100:execution:ParentStateMachine:667102b3-b19c-b7ab-b119-9ec6cf23e505
Result:
one of the first few entries in execution history and task token is part of the parameters. we can exit the loop, grab that, send it back to Api Gateway.
{
"timestamp": "2021-03-12T13:56:58.097000-05:00",
"type": "TaskScheduled",
"id": 3,
"previousEventId": 2,
"taskScheduledEventDetails": {
"resourceType": "states",
"resource": "startExecution.waitForTaskToken",
"region": "us-east-1",
"parameters": "{\"Input\":{\"foo\":\"bar\",\"token\":\"o6QVQ9gls.......=\"},\"StateMachineArn\":\"arn:aws:states:us-east-1:110011001100:stateMachine:ChildStateMachine\",\"Name\":\"MyExecutionName\"}"
}
}

Related

DS SDK -AWS Step functions lambda job cancelled immediately

I am getting this weird result when I try to deploy the lambda step, if I define my lambda step like this
lambda_step = steps.compute.LambdaStep(
"Query Training Results",
parameters={
"FunctionName": execution_input["LambdaFunctionName"],
"Payload": {"TrainingJobName.$": "$.TrainingJobName"},
},
)
For some reason it will automatically just grey out the box meaning the job will be cancelled immediately. If I simply remove the "Payload" part then it will work but the lambda step will still fail because it does not know the training job name that I am trying to pass in the Payload.
I followed this example to the T here. Any suggestions would be greatly appreciated.

How to send the notification on every task execution in a state machine on AW step functions?

I am working on Amazon Step functions to leverage the workflow for multiple Batch jobs. The requirement is such that the Batch jobs should be executed sequentially and whenever a job transition from one to another job then send a notification with the execution status of the tasks to a SNS topic. I need to send a notification for SUCCESS and FAILURE of a task.
I have tried the Execution Events using Cloudwatch event rules, but Execution Events only gives information about the State Machine's execution, not about the Tasks execution.
As you have found states aren't in Cloudwatch events need to add this as a separate step, there is no way around this, have a notify step which either executes a lambda, or sync to SNS.
There is also another way to do this as you can compose step functions of step functions. So you have your parent step function and your child step function. Your child step function could be the batch job itself, and then you can make use of Cloudwatch events on the batch-job-step-function step function:
"BatchJob" : {
"Comment": "This snippet is in the parent step function. It will kick off another step function, called: batch-job-step-function",
"Type": "Task",
"Resource": "arn:aws:states:::states:startExecution.sync",
"Parameters": {
"StateMachineArn": "arn:aws:states:us-east-1:TODO:stateMachine:batch-job-step-function",
"Input": {
"batchJobInput.$": "$$.Execution.Input.batchJobInput"
}
},
"End": true | "Next" : "TODO"
}
Now you can put Cloudwatch Event Rules against: arn:aws:states:us-east-1:TODO:stateMachine:batch-job-step-function

How do I invoke a step function using AWS Lambda ( Python)

I am trying to create a simple step function comprising of two lambda functions. The first lambda function takes two numbers as input from the user (say num1=2, num2 =5), and passes on the sum of the two numbers to the second lambda function. The second lambda function multiplies the output of the first lambda function with a constant (say 10).
I want to be able to get the final answer (which is (2+5)*10 = 70) in this case) as the output of an API invocation.
I am able to execute the Step Function successfully (from the AWS Step Function Console). But the output I get when I invoke the API (integrated with the Step Function) is not a number but as follows:
{
"executionArn": "arn:aws:states:ap-south-1:123456789012:execution:Test_Math:xxx",
"startDate": 1560344276.117
}
How do I get the API call to return the answer (which is the number 70 in this case)?
I have gone already gone through the AWS Documentation and AWS API Gateway with Step Function this question but I am not still not clear.
How can I make a new lambda (or use any of the above two) function which invokes/executes this step function to return the answer?
Are there any other ways to return the answer of a step function via an API call?
My question is somewhat similar to this one Api gateway get output results from step function?.
I tried adding a second method in API Gateway which will call the Step Function with the DescribeExecution action but it did not work.
The mapping template (application/json) for the POST Method with StartExecution action is as follows:
#set($inputRoot = $input.path('$'))
#set($data = $util.escapeJavaScript($input.json('$')))
{
"input": "{ \"num1\": $inputRoot.num1, \"num2\": $inputRoot.num2 }",
"stateMachineArn": "arn:aws:states:ap-south 1:998338******:stateMachine:Test_Math"
}
I created a new GET Method with DescribeExecution action with the following Integration Request details:
Integration type: AWS Service
AWS Service: Step Functions
HTTP method: GET
Action: Describe Execution
Content Handling: Passthrough
Mapping template : application/json
#set($inputRoot = $input.path('$'))
#set($data = $util.escapeJavaScript($input.json('$')))
{
"executionArn": "arn:aws:states:ap-south-1:998338321653:execution:Test_Math:3981114a-da51-411d-9533-8571dc976e2d",
"input": "{ \"num1\": $inputRoot.num1, \"num2\": $inputRoot.num2 }"
}
Please let me know what changes do I need to make in the above to be able to return the answer (70) with an API call.
P.S: I want to deploy my machine learning model using step functions and this is just a simple test which I was trying out.
you can use describe_execution method to fetch the final result of your stepfunction. you have to pass the execution arn as an input to this method.
Find more details here, https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/stepfunctions.html#SFN.Client.describe_execution
Below python code will print the output given the execution arn.
import boto3
client = boto3.client('stepfunctions')
executionArn = ''
response = client.describe_execution(
executionArn=executionArn
)
#print(response)
print(response.get('output'))

Cognito User Migration Trigger - Exception during user migration - Exception Location

We're using a lambda function to respond to the 'User Migration' trigger in AWS Cognito. When something like a syntax error occurs, you can see it in cloud watch logs. However, "Exception during user migration" errors seen on the login page are no where to be found in the cloud watch logs.
Where are we supposed to look for these? I can't find any anything in the documentation and assumed it would have gone to cloud watch.
I can't test it in the lambda interface because one of the parameters being passed into the lambda function will have a function nested within the object and I can't create a test JSON setup that has that. There's also no test trigger for user migration that is pre-built.
Any ideas as to why I can't see this in cloud watch or where the exceptions would be shown would be greatly appreciated.
Unfortunately Cogntio doesn't expose any logs (or metrics, for that matter!).
The closest you can get is to view the lambda's logs in CloudWatch. If you log your response, and watch your lambda's error metric then you should mostly be able to debug issues internal to the lambda.
This does leave a few edge cases:
You won't see anything if the lambda can't be invoked (this would only happen under heavy concurrent loads either on that single lambda, or on all lambdas across your account)
If you return a bad response the lambda will succeed but the trigger action will fail and Cognito will give you a fairly generic message. At this point you're at the mercy of AWS' documentation to work out what's wrong (which can be a bit hit and miss- although StackOverflow always helps!).
You can find an example payload for the lambda in the trigger documentation:
{
"userName": "THE USERNAME",
"request": {
"password": "THE PASSWORD"
},
"response": {
// it is your responsibility to fill this bit in and return the completed object back:
"userAttributes": {
"string": "string",
...
},
"finalUserStatus": "string",
"messageAction": "string",
"desiredDeliveryMediums": [ "string", ... ],
"forceAliasCreation": boolean
}
}
n.b. As an aside, which you might know, but Lambda payloads always have to be in JSON, which does not store functions. So you should always be able to derive a test payload to use in the console.

Api gateway get output results from step function?

I followed tutorial on creating and invoking step functions
I'm getting output in my GET request of api as
{
"executionArn": "arn:aws:states:ap-northeast-1:123456789012:execution:HelloWorld:MyExecution",
"startDate": 1.486772644911E9
}
But, instead of above response I want my step functions output, which is given by end state as below.
{
"name":"Hellow World"
}
How to achieve this?
Update: You can now use Express Step Functions for synchronous requests.
AWS Step Functions are asynchronous and do not immediately return their results. API Gateway methods are synchronous and have a maximum timeout of 29 seconds.
To get the function output from a Step Function, you have to add a second method in API Gateway which will call the Step Function with the DescribeExecution action. The API Gateway client will have to call this periodically (poll) until the returned status is no longer "RUNNING".
Here's the DescribeExecution documentation
Use Express Step Functions instead. This type of Step Functions can be called synchronously. Go to your API Gateway and in the Integration Request section make sure you have the StartSyncExecution action:
After that, go a bit lower in the same page to the Mapping Templates:
and include the following template for the application/json Content-Type:
#set($input = $input.json('$'))
{
"input": "$util.escapeJavaScript($input)",
"stateMachineArn": "arn:aws:states:us-east-1:your_aws_account_id:stateMachine:your_step_machine_name"
}
After that, go back to the Method Execution and go to the Integration Response and then to the Mapping Templates section:
And use the following template to have a custom response from your lambda:
#set ($parsedPayload = $util.parseJson($input.json('$.output')))
$parsedPayload
My testing Step Function is like this:
And my Lambda Function code is:
Deploy your API Gateway stage.
Now, if you go to Postman and send a POST request with any json body, now you have a response like this:
New Synchronous Express Workflows for AWS Step Functions is the answer:
https://aws.amazon.com/blogs/compute/new-synchronous-express-workflows-for-aws-step-functions/
Amazon API Gateway now supports integration with Step Functions StartSyncExecution for HTTP APIs:
https://aws.amazon.com/about-aws/whats-new/2020/12/amazon-api-gateway-supports-integration-with-step-functions-startsyncexecution-http-apis/
First of all the step functions executes asynchronously and API Gateway is only capable of invoking the step function (Starting a flow) only.
If you are waiting for the results of a step function invocation from a web application, you can use AWS IOT WebSockets for this. The steps are as follows.
Setup AWS IOT topic with WebSockets.
Configure the API Gateway and Step functions invocation.
From the Web Frontend subscribe to the IOT Topic as a WebSocket listener.
At the last step (And in error steps) in the Step Functions workflow use AWS SDK to trigger the IOT Topic which will broadcast the results to the Web App running in the browser using WebSockets.
For more details on WebSockets with AWS IOT refer the medium article Receiving AWS IoT messages in your browser using websockets.
Expanding on what #MikeD at AWS says, if you're certain that the Step Function won't exceed the 30 second timeout, you could create a lambda that executes the step function and then blocks as it polls for the result. Once it has the result, it can return it.
It is a better idea to have the first call return immediately with the execution id, and then pass that id into a second call to retrieve the result, once it's finished.