Search code examples
amazon-web-servicesaws-cloudformationaws-step-functions

Passing Input Parameters from one Step Function to another


I do have an Step Function A - which executes a lambda and pull some results. Same Function has a Map Stage which is iterating over results and should call another Step Function from Map State. While calling another Step Function B from the map state i am not able to pass the parameter or that one record as Input to Step Function B.

Please suggest how can i use Input for second step function. Below is the example i am using , orderServiceResponse has a List of orders which I need to iterate and pass that one order to next step function.

"Validate-All" : {
       "Type" : "Map",
       "InputPath" : "$.orderServiceResponse",
       "ItemsPath" : "$.orders",
       "MaxConcurrency" : 5,
       "ResultPath" : "$.orders",
        "Iterator" : {
                "StartAt" : "Validate" , 
                "States" :{
                      "Validate" : {
                        "Type" : "Task"
                        "Resource" : "arn:aws:states:::states:startExecution.sync:2",
                        "Parameters" {
                                   "Input" : "$.orders",
                                   "StateMachineArn" : "{arn of Step Function B }
                            },
                          "End" : true
                    }
                 } 

Solution

  • TL;DR Use Parameters with Map Context to add the full input object to each Map element iteration.

    You have an array of data you want to process elementwise in a Map State. By default, Map only passes the array element's data to the map iterator. But we can add additional context to each iteration.

    Here is an example - the important bits are commented:

    {
      "StartAt": "MapState",
      "States": {
        "MapState": {
          "Type": "Map",
          "ResultPath": "$.MapResult",
          "Next": "Success",
          // the map's elements of each get the following:
          "Parameters": { 
            "Index.$": "$$.Map.Item.Index", // the array element's data (we only get this by default)
            "Order.$": "$$.Map.Item.Value", // the array element's index 0,1,2...
            "FullInput.$": "$" // a copy of the the full input object <-- this is what you were looking for
          },
          "Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "Fail" }],
          // substitute your iterator:
          "Iterator": {
            "StartAt": "MockTask",
            "States": {
              "MockTask": {
                "End": true,
                "Type": "Task",
                "Resource": "arn:aws:lambda:us-east-1:xxxxxxxxxxxx",
                "Parameters": {
                  "expression": "`Order ${$.Order.OrderID} was ordered by ${$.FullInput.CustomerName}`",
                  "expressionAttributeValues": {
                    "$.Order.OrderID.$": "$.Order.OrderID",
                    "$.FullInput.CustomerName.$": "$.FullInput.CustomerName"
                  }
                }
              }
            }
          },
          "ItemsPath": "$.Orders"
        },
        "Success": { "Type": "Succeed" },
        "Fail": { "Type": "Fail" }
      }
    }
    

    Execution Input, 3 Orders:

    {
      "CustomerID": 1,
      "CustomerName": "Morgan Freeman",
      "OtherInfo": { "Foo": "Bar" },
      "Orders": [{ "OrderID": "A", "Status": "Fulfilled" }, { "OrderID": "B", "Status": "Pending" }, { "OrderID": "C", "Status": "Cancelled" }]
    }
    

    Map Iteration 0 Input:

    {
      "Order": { "OrderID": "A", "Status": "Fulfilled" },
      "Index": 0,
      "FullInput": {  "CustomerID": 1, "CustomerName": "Morgan Freeman", "OtherInfo": { "Foo": "Bar" }, "Orders": [{...
    

    Execution Output MapResult key

    {
      "MapResult": [
        "Order A was ordered by Morgan Freeman",
        "Order B was ordered by Morgan Freeman",
        "Order C was ordered by Morgan Freeman"
      ]
    ...
    }