Please enable JavaScript to view this website.

Skip to main content

State Types

State Types

As a reminder, the state type is given by the value of the "Type" field, which MUST appear in every State object.

States describe tasks (units of work), or specify flow control (e.g. Choice).

Table of State Types and Fields

Many fields can appear in more than one state type. The table below summarizes which fields can appear in which states. It excludes fields that are specific to one state type.

States
TaskMapPassWaitChoiceSucceedFail
TypeRequiredRequiredRequiredRequiredRequiredRequiredRequired
CommentAllowedAllowedAllowedAllowedAllowedAllowedAllowed
InputPath, OutputPathAllowedAllowedAllowedAllowedAllowedAllowed
One of: Next or "End":trueRequiredRequiredRequiredRequired
ResultPathAllowedAllowedAllowed
ParametersAllowedAllowedAllowed
ResultSelectorAllowedAllowed
CatchAllowedAllowed

Pass State

The Pass State (identified by "Type":"Pass") by default passes its input to its output, performing no work with task resources; however, it can do work such as performing mathematical operations on data from previous states.

A Pass State MAY have a field named "Result". If present, its value is treated as the output of a virtual task, and placed as prescribed by the "ResultPath" field, if any, to be passed on to the next state. If "Result" is not provided, the output is the input. Thus if neither "Result" nor "ResultPath" are provided, the Pass State copies its input through to its output.

Here is an example of a Pass State that injects some fixed data into the state machine, probably for testing purposes.

"No-op": {
"Type": "Pass",
"Result": {
"x-datum": 0.381018,
"y-datum": 622.2269926397355
},
"ResultPath": "$.coords",
"Next": "End"
}

Suppose the input to this state were as follows:

{
"geoRefOf": "Home"
}

Then the output would be:

{
"geoRefOf": "Home",
"coords": {
"x-datum": 0.381018,
"y-datum": 622.2269926397355
}
}

Task State

The Task State (identified by "Type":"Task") causes the interpreter to execute the work identified by the state’s "Resource" field.

Here is an generalized example:

"TaskState": {
"Comment": "Task State example",
"Type": "Task",
"Resource": "Some:Resource",
"Parameters": {
"SomeParam": 1
},
"Next": "NextState",
"TimeoutSeconds": 300,
}

A Task State MUST include a "Resource" field, whose value MUST be a string that uniquely identifies the specific task to execute. See Available Task Resources for the complete list of Resource options.

A Task State MAY include a "Parameters" field, whose value MUST be a Payload Template. A Task State MAY include a "ResultSelector" field, whose value MUST be a Payload Template.

Tasks can optionally specify timeouts. Timeouts are specified in seconds and MUST be positive integers and if not provided, the default value of "TimeoutSeconds" is 60.

If the state runs longer than the specified timeout then the interpreter fails the state with a States.Timeout Error Name.

Choice State

A Choice State (identified by "Type":"Choice") adds branching logic to a state machine.

A Choice State MUST have a "Choices" field whose value is a non-empty array. Each element of the array MUST be a JSON object and is called a Choice Rule. A Choice Rule may be evaluated to return a boolean value. A Choice Rule at the top level, i.e. which is a member of the "Choices" array, MUST have a "Next" field, whose value MUST match a state name.

The interpreter attempts pattern-matches against the top-level Choice Rules in array order and transitions to the state specified in the "Next" field on the first Choice Rule where there is an exact match between the input value and a member of the comparison-operator array.

Here is an example of a Choice State.

"StateX": {
"Type" : "Choice",
"Choices": [
{
"Not": {
"Variable": "$.type",
"StringEquals": "Private"
},
"Next": "Handle Public"
},
{
"Variable": "$.stringVar",
"StringEquals": "MTSL is Neat",
"Next": "Handle String"
},
{
"And": [
{
"Variable": "$.value",
"IsPresent": true
},
{
"Variable": "$.value",
"IsNumeric": true
},
{
"Variable": "$.value",
"NumericGreaterThanEquals": 20
},
{
"Variable": "$.value",
"NumericLessThan": 30
}
],
"Next": "Handle Value In Twenties"
}
],
"Default": "StateY"
}

In this example, suppose the machine is started with an input value of:

{
"type": "Private",
"value": 22,
"stringVar": "example"
}

Then the interpreter will transition to the "Handle Value In Twenties" state, based on the "value" field.

A Choice Rule MUST be either a Boolean Expression or a Data-test Expression.

Boolean expression

A Boolean Expression is a JSON object which contains a field named "And", "Or", or "Not". If the field name is "And" or "Or", the value MUST be an non-empty object array of Choice Rules, which MUST NOT contain "Next" fields; the interpreter processes the array elements in order (top to bottom), performing the boolean evaluations and ceasing array processing when the boolean value has been unambiguously determined.

The value of a Boolean Expression containing a "Not" field MUST be a single Choice Rule, that MUST NOT contain a "Next" field; it returns the inverse of the boolean to which the Choice Rule evaluates.

Data-test expression

A Data-test Expression Choice Rule is an assertion about a field and its value which yields a boolean depending on the data. A Data-test Expression MUST contain a field named "Variable" whose value MUST be a Path. Additionally, each choice rule MUST contain exactly one field containing a comparison operator. Below is an example of a data-test expression.

{
"Variable": "$.cycleCount",
"NumericLessThanPath": "$.maxCycleCount"
}

The following comparison operators are supported:

  1. StringEquals, StringEqualsPath

  2. StringLessThan, StringLessThanPath

  3. StringGreaterThan, StringGreaterThanPath

  4. StringLessThanEquals, StringLessThanEqualsPath

  5. StringGreaterThanEquals, StringGreaterThanEqualsPath

  6. NumericEquals, NumericEqualsPath

  7. NumericLessThan, NumericLessThanPath

  8. NumericGreaterThan, NumericGreaterThanPath

  9. NumericLessThanEquals, NumericLessThanEqualsPath

  10. NumericGreaterThanEquals, NumericGreaterThanEqualsPath

  11. BooleanEquals, BooleanEqualsPath

  12. TimestampEquals, TimestampEqualsPath

  13. TimestampLessThan, TimestampLessThanPath

  14. TimestampGreaterThan, TimestampGreaterThanPath

  15. TimestampLessThanEquals, TimestampLessThanEqualsPath

  16. TimestampGreaterThanEquals, TimestampGreaterThanEqualsPath

  17. IsNull

    Note: This means the value is the built-in JSON literal null.

  18. IsPresent

    Note: In this case, if the Variable-field Path fails to match anything in the input no exception is thrown and the Choice Rule just returns false.

  19. IsNumeric

  20. IsString

  21. IsBoolean

  22. Includes

  23. IsTimestamp

For those operators that end with "Path", the value MUST be a Path, to be applied to the state’s effective input to yield a value to be compared with the value yielded by the Variable path.

For each operator which compares values, if the values are not both of the appropriate type (String, number, boolean, or Timestamp) the comparison will return false. Note that a field which is thought of as a timestamp could be matched by a string-typed comparator.

The various String comparators compare strings character-by-character with no special treatments such as case-folding, white-space collapsing, or Unicode form normalization.

Note that for interoperability, numeric comparisons should not be assumed to work with values outside the magnitude or precision representable using the IEEE 754-2008 "binary64" data type. In particular, integers outside of the range [-(253)+1, (253)-1] might fail to compare in the expected way.

A Choice State MAY have a "Default" field, whose value MUST be a string whose value MUST match a State name; that state will execute if none of the Choice Rules match. The interpreter will raise a runtime "States.NoChoiceMatched" error if a Choice State fails to match a Choice Rule and no "Default" transition was specified; hence, it is recommended that a Default field be used. You can also think of the Default field as the else statement in the traditional if statement in C.

A Choice State MUST NOT be an End state.

Wait State

A Wait State (identified by "Type":"Wait") causes the interpreter to delay the machine from continuing for a specified time. The time is specified as a wait duration, specified in the Seconds field and is in seconds.

For example, the following Wait State introduces a ten second delay into a state machine:

"Wait ten seconds" : {
"Type" : "Wait",
"Seconds" : 10,
"Next": "NextState"
}

A Wait State MUST contain a "Seconds" property.

Succeed State

The Succeed State (identified by "Type":"Succeed") either terminates a state machine successfully or ends an iteration of a Map State. The output of a Succeed State is the same as its input, possibly modified by "InputPath" and/or "OutputPath".

The Succeed State is a useful target for Choice-State branches that don't do anything except terminate the machine.

Here is an example:

"SuccessState": {
"Type": "Succeed"
}

Because Succeed States are terminal states, they have no "Next" field.

Fail State

The Fail State (identified by "Type":"Fail") terminates the machine and marks it as a failure.

Here is an example:

"FailState": {
"Type": "Fail",
"Error": "ErrorA",
"Cause": "Everything fails"
}

A Fail State MUST have a string field named "Error", used to provide an error name that can be used for error handling (Catch), operational, or diagnostic purposes. A Fail State MUST have a string field named "Cause", used to provide a human-readable message.

Because Fail States are terminal states, they have no "Next" field.

Map State

The Map State (identified by "Type": "Map") causes the interpreter to process all the elements of an array with the processing of each element independent of the others. This document uses the term "iteration" to describe each such nested execution.

The Map State applies a single state machine to multiple input elements.

There are several fields which may be used to control the execution. To summarize:

  1. The "Iterator" field’s value is an object that defines a state machine which will process each element of the array.

  2. The "ItemsPath" field’s value is a Reference Path identifying where in the effective input the array field is found.

Consider the following example input data:

{
"MemoryMap": {
"MemoryAddresses": [
{ "Address": "5004", "LengthToRead": "04" },
{ "Address": "5008", "LengthToRead": "04" },
{ "Address": "500A", "LengthToRead": "04" },
{ "Address": "500E", "LengthToRead": "04" }
]
}
}

Suppose it is desired to read each memory location. Here is an example of an appropriate Map State.

"Read All": {
"Type": "Map",
"InputPath": "$.MemoryMap",
"ItemsPath": "$.MemoryAddresses",
"Iterator": {
"StartAt": "Read From Address",
"States": {
"Read From Address": {
"Type": "Task",
"Resource": "OpenLink:SendCommand",
"Parameters": {
"MessageType": "01",
"IsWrite": false,
"RouteType": "Tool",
"CommandBody": "States.Format('{}{}', $.Address, $.LengthToRead)"
},
"End": true
}
}
},
"ResultPath": "$.MemoryMap.ReadResponses",
"End": true
}

In the example above, the "Read From Address" State will be executed once for each element of the "MemoryAddresses" field. The input to one iteration will be:

{
"Address": "5004",
"LengthToRead": "04"
}

In the example above, the specified ResultPath tells the interpreter to append the results to the original input at the .MemoryMap.ReadResponses path, so the final output would look like:

{
"MemoryMap": {
"MemoryAddresses": [
{ "Address": "5004", "LengthToRead": "04" },
{ "Address": "5008", "LengthToRead": "04" },
{ "Address": "500A", "LengthToRead": "04" },
{ "Address": "500E", "LengthToRead": "04" }
]
},
"ReadResponses": {
{...}, // The JSON response returned from the OpenLinkCommand Task
{...},
{...},
{...}
}
}

Map State input/output processing

The "InputPath" field operates as usual, selecting part of the raw input - in the example, the value of the "MemoryMap" field - to serve as the effective input.

A Map State MAY have a "ItemsPath" field, whose value MUST be a Reference Path. The Reference Path is applied to the effective input and MUST identify a field whose value is a JSON array.

The default value of "ItemsPath" is "$", which is to say the whole effective input. So, if a Map State has neither an "InputPath" nor a "ItemsPath" field, it is assuming that the raw input to the state will be a JSON array.

The input to each invocation, by default, is a single element of the array field identified by the "ItemsPath" value, but may be overridden using the "Parameters" field.

In each iteration, within the Map State (but not child states within an Iterator field), the Context Object will have an object field named "Map" which contains an object field named "Item" which in turn contains an integer field named "Index" whose value is the (zero-based) array index being processed in the iteration and a field named "Value", whose value is the array element being processed.

A Map State’s result is an array containing one element for each element of the ItemsPath input array, in the same order.

The interpreter will invoke the Iterator once for each array element in the order of their appearance in the input, and will not start an iteration until the previous iteration has completed execution.

Map State Iterator definition

A Map State MUST contain an object field named "Iterator" which MUST contain fields named "States" and "StartAt", whose meanings are exactly like those in the top level of a State Machine.

A state in the "States" field of an "Iterator" field MUST NOT have a "Next" field that targets a field outside of that "States" field. A state MUST NOT have a "Next" field which matches a state name inside an "Iterator" field’s "States" field unless it is also inside the same "States" field.

Put another way, states in an Iterator’s "States" field can transition only to each other, and no state outside of that "States" can transition into it.

If any iteration fails, due to an unhandled error or by transitioning to a Fail state, the entire Map State is considered to have failed and all the iterations are terminated. If the error is not handled by the Map State, the interpreter should terminate the machine execution with an error.

Unlike a Fail State, a Succeed State within a Map merely terminates its own iteration only, not all of the iterations. A Succeed State passes its input through as its output, possibly modified by "InputPath" and "OutputPath".