Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting started with Step Functions and I can't get Choice to work correctly

I'm doctoring up my first step function, and as a newb into this I am struggling to make this work right. The documentation on AWS is helpful but lacks examples of what I am trying understand. I found a couple similar issues on the site here, but they didn't really answer my question either.

I have a test Step Function that works really simply. I have a small Lambda function that kicks out a single line JSON with a "Count" from a request in a DynamoDB:

def lambda_handler(event, context):
    """lambda_handler

    Keyword arguments:
    event -- dict -- A dict of parameters to be validated.
    context -- 

    Return:
    json object with the hubID from DynamoDB of the new hub. 

    Exceptions:
    None
    """
    # Prep the Boto3 resources needed
    dynamodb        = boto3.resource('dynamodb')
    table           = dynamodb.Table('TransitHubs')

    # By default we assume there are no new hubs
    newhub = { 'Count' : 0 }

    # Query the DynamoDB to see if the name exists or not:
    response = table.query(
        IndexName='Status-index',
        KeyConditionExpression=Key('Status').eq("NEW"),
        Limit=1
    )

    if response['Count']:
        newhub['Count'] = response['Count']

    return json.dumps(newhub)

A normal output would be:

{ "Count": 1 }

And then I create this Step Function:

{
  "StartAt": "Task",
  "States": {
        "Task": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-west-2:OMGSUPERSECRET:function:LaunchNode-get_new_hubs",
      "TimeoutSeconds": 60,
      "Next": "Choice"
    },
    "Choice": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.Count",
          "NumericEquals": 0,
          "Next": "Failed"
        },
        {
          "Variable": "$.Count",
          "NumericEquals": 1,
          "Next": "Succeed"
        }
      ]
    },
    "Succeed": {
      "Type": "Succeed"
    },
    "Failed": {
      "Type": "Fail"
    }
  }
}

So I kick off the State Function and I get this output:

TaskStateExited

{
  "name": "Task",
  "output": {
    "Count": 1
  }
}

ChoiceStateEntered

{
  "name": "Choice",
  "input": {
    "Count": 1
  }
}

ExecutionFailed

{
  "error": "States.Runtime",
  "cause": "An error occurred while executing the state 'Choice' (entered at the event id #7). Invalid path '$.Count': The choice state's condition path references an invalid value."
}

So my question: I don't get why this is failing with that error message. Shouldn't Choice just pick up that value from the JSON? Isn't the default "$" input the "input" path?

like image 392
Geoff Sweet Avatar asked Apr 03 '18 19:04

Geoff Sweet


2 Answers

I have figured out what the issue is, and here it is:

In my Python code, I was attempting to json.dumps(newhub) for the response thinking that what I needed was a string output representing the json formatted response. But it appears that is incorrect. When I alter the code to be simply "return newhub" and return the DICT, the step-functions process accepts that correctly. I'm assuming it parses the DICT to JSON for me? But the output difference is clearly obvious:

old Task output from above returning json.dumps(newhub):

{
  "name": "Task",
  "output": {
    "Count": 1
  }
}

new Task output from above returning newhub:

{
  "Count": 1
}

And the Choice now correctly matches the Count variable in my output.

like image 108
Geoff Sweet Avatar answered Sep 22 '22 08:09

Geoff Sweet


In case this is helpful for someone else. I also experienced the kind of error you did ( you had the below... just copy-pasting yours... )

{
"error": "States.Runtime",
"cause": "An error occurred while executing the state 'Choice' (entered at the event id #7). Invalid path '$.Count': The choice state's condition path references an invalid value."
}

But my problem turned out when I was missing the "Count" key all together.

But I did not want verbose payloads.

But per reading these docs I discovered I can also do...

"Choice": {
"Type": "Choice",
"Choices": [
  {
    "And": [
      {
          "Variable": "$.Count",
          "IsPresent": true
          },
      {
          "Variable": "$.Count",
          "NumericEquals": 0,
          }
      ],
    "Next": "Failed"
    },
  {
    "And": [
      {
          "Variable": "$.Count",
          "IsPresent": true
          },
      {

          "Variable": "$.Count",
          "NumericEquals": 1,
          }
      ],
    "Next": "Succeed"
    }
  ]
},
like image 21
HeyWatchThis Avatar answered Sep 22 '22 08:09

HeyWatchThis