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

Filtering input array in a Step Function and redirect to different states


Given the following input for a State, is it possible to redirect the FAILS to one state and the SUCCESSES to another?

[
  {
    "Status": "SUCCESS",
    "Stack": "metadata"
  },
  {
    "Status": "FAILED",
    "Stack": "metadata-roles"
  },
  {
    "Status": "FAILED",
    "Stack": "master-storage"
  },
  {
    "Status": "SUCCESS",
    "Stack": "appstream-storage"
  },
  {
    "Status": "SUCCESS",
    "Stack": "capability-storage"
  },
  {
    "Status": "SUCCESS",
    "Stack": "action-storage"
  },
  {
    "Status": "SUCCESS",
    "Stack": "domain-action-storage"
  },
  {
    "Status": "FAILED",
    "Stack": "auth0-clients"
  },
  {
    "Status": "FAILED",
    "Stack": "ecr-repository"
  },
  {
    "Status": "FAILED",
    "Stack": "ecr-replication"
  }
]

I think I need a Choice state but I cannot figure out if the language supports this.

If all I have are SUCCESS items, then the Choice goes to a All succeed state, and if I have at least one item with FAILED, then the Choice goes to a Partially succeed state. If I could have the failed items carried over into the Partially succeed would be nice, but not mandatory.


Solution

  • I think you want to do something like the following. The idea here is to use a filter expression in JSON Path Processing to split the array into two lists, one for failed and one for success. You then send that into a Parallel state where you can have one branch for your successful items and one for your failed ones.

    This example is a bit verbose but will allow you to drop it into your account and see how it works. I reality, the output would likely come from a Task and you could use the ResultSelector to format the output into separate items without needing a Pass state. As well, in the branches for the Parallel state, you could use InputPath or Parameters to grab the right part of the input without needing to add a Pass state if you didn't want to.

    enter image description here

    {
      "Comment": "A example to show how to send data to two separate states",
      "StartAt": "Generate Input",
      "States": {
        "Generate Input": {
          "Type": "Pass",
          "Result": [
            {
              "Status": "SUCCESS",
              "Stack": "metadata"
            },
            {
              "Status": "FAILED",
              "Stack": "metadata-roles"
            },
            {
              "Status": "FAILED",
              "Stack": "master-storage"
            },
            {
              "Status": "SUCCESS",
              "Stack": "appstream-storage"
            },
            {
              "Status": "SUCCESS",
              "Stack": "capability-storage"
            },
            {
              "Status": "SUCCESS",
              "Stack": "action-storage"
            },
            {
              "Status": "SUCCESS",
              "Stack": "domain-action-storage"
            },
            {
              "Status": "FAILED",
              "Stack": "auth0-clients"
            },
            {
              "Status": "FAILED",
              "Stack": "ecr-repository"
            },
            {
              "Status": "FAILED",
              "Stack": "ecr-replication"
            }
          ],
          "Next": "Split"
        },
        "Split": {
          "Type": "Pass",
          "Parameters": {
            "success.$": "$.[?(@.Status == 'SUCCESS')]",
            "failed.$": "$.[?(@.Status == 'FAILED')]"
          },
          "Next": "Parallel"
        },
        "Parallel": {
          "Type": "Parallel",
          "End": true,
          "Branches": [
            {
              "StartAt": "Get Success",
              "States": {
                "Get Success": {
                  "Type": "Pass",
                  "OutputPath": "$.success",
                  "Next": "Process Successful"
                },
                "Process Successful": {
                  "Type": "Pass",
                  "End": true
                }
              }
            },
            {
              "StartAt": "Get Failed",
              "States": {
                "Get Failed": {
                  "Type": "Pass",
                  "OutputPath": "$.failed",
                  "Next": "Process Failed"
                },
                "Process Failed": {
                  "Type": "Pass",
                  "End": true
                }
              }
            }
          ]
        }
      }
    }