Given this input:
{
"foo": "bar",
"ttl": 100
}
I'm using AWS step functions to wait until something is ready but I don't want to wait for ever so one of my "states" is a time-to-live value that gets decremented. When the TTL reaches 0 the execution stops:
{
"Comment": "State machine to check the status of something until it's ready or we waiting long enough",
"StartAt": "get-status",
"States": {
"get-status": {
"Type": "Task",
"Resource": "arn:aws:lambda:region:account:function:get-status-lambda",
"ResultPath": "$.status",
"Next" : "is-ready"
},
"is-ready": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.status",
"StringEquals": "CREATE_COMPLETE",
"Next": "ready"
},
{
"Variable": "$.status",
"StringMatches": "*ROLLBACK_COMPLETE*",
"Next": "creation-failed"
},
{
"Variable": "$.ttl",
"NumericEquals": 0,
"Next": "ttl-expired"
}
],
"Default": "wait-a-bit"
},
"wait-a-bit": {
"Type": "Wait",
"Seconds": 10,
"Next": "decrement-ttl"
},
"decrement-ttl": {
"Type": "Task",
"Resource": "arn:aws:lambda:region:account:function:decrement-ttl-lambda",
"InputPath": "$.ttl",
"ResultPath": "$.ttl",
"Next": "get-status"
},
"ttl-expired": {
"Type": "Fail",
"Cause": "Create dumper stack TTL reached 0!"
},
"creation-failed": {
"Type": "Fail",
"Cause": "A error during the cloudformation stack prevented its creation."
},
"ready": {
"Type": "Pass",
"End": true
}
}
}
The state machine above works. It adds a status
property to the JSON and it does decrement the ttl
value. That said it seems overkill to have to use a lambda function just to decrement an int value!
Could Intrinsic Functions come to the rescue, namely the States.MathAdd
one?
If I modify the decrement-ttl
state in the definition above with this...
"decrement-ttl": {
"Type": "Pass",
"Parameters": {
"ttl.$": "States.MathAdd($.ttl, -1)"
},
"ResultPath": "$.ttl",
"Next": "get-status"
},
... my json payload becomes and the execution eventually breaks.
{
"foo": "bar",
"ttl": {
"ttl": 9
},
"status": "meh"
}
My question is: is it possible to use an intrinsic function to increase or decrease an int value and the result put it back into a property?
The problem I have is an object { "ttl": 9}
is put back, not the value 9
.
I tried using an OutputPath
selector but it didn't work...
Here are two options that decrement the TTL while retaining the same shape as the input:
A single Pass state works if your input keys are known and fixed. List all the input keys in the Parameters
field explicitly:
"decrement-ttl": {
"Type": "Pass",
"Parameters": {
"ttl.$": "States.MathAdd($.ttl, -1)",
"foo.$": "$.foo",
},
"Next": "get-status"
},
Case #1 won't work if your input keys are not known in advance or change between iterations. A generic solution requires two Pass states. The first decrements the counter. But it outputs the wrong shape: {ttl: {ttl: 0}}
. The second Pass fixes the shape to match the input. It merges the TTL with the original payload using the JsonMerge
intrinsic function.
"decrement-ttl": {
"Type": "Pass",
"Parameters": {
"ttl.$": "States.MathAdd($.ttl, -1)"
},
"ResultPath": "$.ttl",
"Next": "merge"
},
"merge": {
"Type": "Pass",
"Parameters": {
"merged.$": "States.JsonMerge($, $.ttl, false)"
},
"OutputPath": "$.merged",
"Next": "get-status"
}