Step Functions para no morir. Parte 2: Lenguaje ASL

Giuliana Olmos - Feb 8 '22 - - Dev Community

Hola!
Gif patricio diciendo hola

Fuaaa, casi no llegué a la segunda semana de posteo.
Es este segundo post vamos a ver los siguientes temas:

  • Que es ASL?
  • Tipos de State
  • Manejo de Errores
  • Serverless

¿Qué es ASL?

Cuando hablamos de ASL en AWS hacemos referencia al Amazon States Language.
Es un lenguaje estructurado basado en el formato JSON que se utiliza para definir las máquinas de estado, las cuales, a fin de cuentas, son una colección de Tasks. Estas Tasks pueden realizar una tarea (Task state), determinar a qué estados se debe pasar a continuación (Choice state), detener una ejecución con un error (Fail state), entre otros.

State Machines en ASL

Un ejemplo de una state machine orquestada en asl sería el siguiente:

{
  "Comment": "A Hello World example demonstrating various state types of the Amazon States Language",
  "StartAt": "Pass",
  "States": {
    "Pass": {
      "Comment": "A Pass state passes its input to its output, without performing work. Pass states are useful when constructing and debugging state machines.",
      "Type": "Pass",
      "Next": "Hello World example?"
    },
    "Hello World example?": {
      "Comment": "A Choice state adds branching logic to a state machine. Choice rules can implement 16 different comparison operators, and can be combined using And, Or, and Not",
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.IsHelloWorldExample",
          "BooleanEquals": true,
          "Next": "Yes"
        },
        {
          "Variable": "$.IsHelloWorldExample",
          "BooleanEquals": false,
          "Next": "No"
        }
      ],
      "Default": "Yes"
    },
    "Yes": {
      "Type": "Pass",
      "Next": "Hello World"
    },
    "No": {
      "Type": "Fail",
      "Cause": "Not Hello World"
    },
    "Hello World": {
      "Type": "Pass",
      "End": true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

En las estructuras de las state machine contamos con los siguientes campos:

  • Comment (Opcional) : Es en donde escribimos la descripción, ya sea de la tarea o de la máquina de estado.
  • StartAt (Obligatorio): Indica el nombre en formato string que coincide exactamente con la tarea que inicia la máquina de estado (es Case Sensitive)
  • TimeoutSeconds (Opcional): Indica la cantidad máxima de segundos que puede durar la ejecución de la máquina.
  • States (Obligatorio): Contiene el set de tareas que componen la máquina de estado.

Tipos de States

A la hora de trabajar con máquinas de estado, tenemos un total de 8 tipos de States que nos van a ayudar a la hora de la orquestación.

Task

Un State de tipo Task representa una única unidad de trabajo realizada por una máquina de estado.
Una Task realiza el trabajo mediante una actividad o una función de AWS Lambda, o pasando parámetros para consumir APIs de otros servicios.

 "ActivityState": {
  "Type": "Task",
  "Resource": "arn:aws:states:us-east-1:123456789012:activity:HelloWorld",
  "Next": "NextState"
}
Enter fullscreen mode Exit fullscreen mode

Los campos campos obligatorios son;

  • Type: En este caso estamos hablando del tipo Task.
  • Resource: Un ARN que identifica de forma inequívoca la tarea específica que se va a ejecutar.
  • Next o End: El campo next indica cual es la tarea que se va a correr una vez que se termina de ejecutar la tarea actual. Si queremos que el flujo finalice en esta tarea vamos a reemplazarlo por un “End” : true

Pass

Este state toma la información del input y la entrega como output sin hacer ningún trabajo o actividad.
Es decir, , solo pass la información.

Guiño Guiño Jefe Gorgory

Bueno, ahora en serio...
Este es un ejemplo de un State de tipo Pass.

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

Enter fullscreen mode Exit fullscreen mode

En este tipo de state los campos obligatorios son Type y Next o End.
Lo opcionales son

  • Result : Es la data que se pasa a la siguiente tarea, y en caso de tener un ResulthPath, es la posición que toma dentro del resultado.
  • ResultPath: Especifica dónde (en la entrada) se coloca la "salida" de la tarea virtual especificada en Result.

Es decir, si la entrada es

{
  "georefOf": "Home"
}
Enter fullscreen mode Exit fullscreen mode

La salida combinando el Result con el ResulthPath es

{
  "georefOf": "Home",
  "coords": {
    "x-datum": 0.381018,
    "y-datum": 622.2269926397355
  }
}
Enter fullscreen mode Exit fullscreen mode

Wait

Este state espera hasta el tiempo asignado y luego continúa con la task siguiente

"wait_ten_seconds": {
    "Type": "Wait",
    "Seconds": 10,
    "Next": "NextState"
}
Enter fullscreen mode Exit fullscreen mode

El tiempo asignado pueden ser segundos, declarándose en el campo Seconds, o puede ser un tiempo absoluto declarando la fecha en el campo Timestamp.

 "Timestamp": "2016-03-14T01:59:00Z"
Enter fullscreen mode Exit fullscreen mode

Choice

Es la que agrega la lógica de ramificación a la máquina de estado.

 "ChoiceState": {
    "Type": "Choice",
    "Choices": [
        {
            "Variable": "$.name",
            "StringEquals": "Blancanieves",
            "Next": "Eat Apple"
        }
    ],
    "Default": "Not Eat Apple"
}
Enter fullscreen mode Exit fullscreen mode

Los campos obligatorios son Type y Choices.
En Choices van las distintas ramificaciones que puede tener la máquina de estado.
Existen distintos tipos de operadores de comparación, sus nombres son bastantes descriptivos.

  • And
  • BooleanEquals,BooleanEqualsPath
  • IsBoolean
  • IsNull
  • IsNumeric
  • IsPresent
  • IsString
  • IsTimestamp
  • Not
  • NumericEquals,NumericEqualsPath
  • NumericGreaterThan,NumericGreaterThanPath
  • NumericGreaterThanEquals,NumericGreaterThanEqualsPath
  • NumericLessThan,NumericLessThanPath
  • NumericLessThanEquals,NumericLessThanEqualsPath
  • Or
  • StringEquals,StringEqualsPath
  • StringGreaterThan,StringGreaterThanPath
  • StringGreaterThanEquals,StringGreaterThanEqualsPath
  • StringLessThan,StringLessThanPath
  • StringLessThanEquals,StringLessThanEqualsPath
  • StringMatches
  • TimestampEquals,TimestampEqualsPath
  • TimestampGreaterThan,TimestampGreaterThanPath
  • TimestampGreaterThanEquals,TimestampGreaterThanEqualsPath
  • TimestampLessThan,TimestampLessThanPath
  • TimestampLessThanEquals,TimestampLessThanEqualsPath

Es recomendable que la Task Choice tenga un campo llamado Default para que en caso de que no coincida con ninguna choice pueda continuar el flujo.

Parallel

El state de tipo Parallel te permite ejecutar tareas de manera paralela.

{
    "LookupCustomerInfo": {
        "Type": "Parallel",
        "End": true,
        "Branches": [
            {
                "StartAt": "LookupAddress",
                "States": {
                    "LookupAddress": {
                        "Type": "Task",
                        "Resource": "arn:aws:lambda:us-east-1:123456789012:function:AddressFinder",
                        "End": true
                    }
                }
            },
            {
                "StartAt": "LookupPhone",
                "States": {
                    "LookupPhone": {
                        "Type": "Task",
                        "Resource": "arn:aws:lambda:us-east-1:123456789012:function:PhoneFinder",
                        "End": true
                    }
                }
            }
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

Los campos obligatorios son el Type, Next o End y Branches.
El campo Branches son los flujos que se van a ejecutar de manera paralela, y siguen la sintaxis de una máquina de estado.

Succeed

Es la task utilizada para terminar las ejecución de manera exitosa. Es un tipo de state que no necesita un campo Next o End.

"SuccessState": {
    "Type": "Succeed"
}
Enter fullscreen mode Exit fullscreen mode

Fail

Termina la ejecución con de la máquina de estado con una ejecución fallida.
Este state tampoco necesita de un campo Next o End.

"FailState": {
    "Type": "Fail",
    "Cause": "Invalid response.",
    "Error": "ErrorA"
}
Enter fullscreen mode Exit fullscreen mode

Los campos Cause y Error son opcionales.

Map

Es el state que permite ejecutar varios pasos para cada iteración de un elemento.
Es decir, mientras que el Parallel ejecuta distintos flujos al mismo tiempo, el Map ejecuta el mismo flujo para distintos elementos.

"Validate-All": {
    "Type": "Map",
    "Iterator": {
        "StartAt": "Validate",
        "States": {
            "Validate": {
                "Type": "Task",
                "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ship-val",
                "End": true
            }
        }
    },
    "End": true
}
Enter fullscreen mode Exit fullscreen mode

Los campos obligatorios son Type e Iterator, en este campo se define la máquina de estado que va a procesar la data.

Manejo de errores

Para el manejo de errores tenemos dos campos que podemos utilizar dentro de las states.

  • Retry : se va a encargar de la cantidad de reintentos de un state en caso de que falle. Solo está permitido en los states de tipo Task y Parallel.

  • Catch: Se encarga de atrapar el error y redireccionarlo al flujo al que corresponde. Solo está permitido en los states de tipo Task, Map y Parallel.

Ejemplo

Suponiendo que tenemos un state de tipo Task, necesitamos que

  • Si falla la ejecución, deben hacerse 3 intentos.
  • Cuando falla la tercera ejecución, queremos manejar el error para enviarlo a un flujo en particular.
"ValidateCreditCard": {
    "Type": "Task",
    "Resource": "arn:aws:states:us-east-1:123456789012:function:Validate",
    "Retry": [
        {
            "ErrorEquals": [
                "States.ALL"
            ],
            "MaxAttempts": 3
        }
    ],
    "Catch": [
        {
            "ErrorEquals": [
                "Error"
            ],
            "Next": "Format Error Response",
        }
    ],
    "Next": "NextState"
}
Enter fullscreen mode Exit fullscreen mode

Para los reintentos tenemos el campo Retry, y dentro de este tenemos otros dos campos importantes.

  • ErrorEquals: va a ser la condición para los reintentos, es decir, solo cuando el error coincida con el mencionado, vamos a tener un reintento.
  • MaxAttemps: es la cantidad de reintentos para nuestra ejecución.
"Retry": [
    {
        "ErrorEquals": [
            "States.ALL"
        ],
        "MaxAttempts": 3
    }
]
Enter fullscreen mode Exit fullscreen mode

Para el manejo de error vamos a usar el campo Catch, y este lleva los siguientes campos.

  • ErrorEquals: va a ser el error que queremos atrapar
  • Next es el nombre del próximo step si coincide con el error.
"Catch": [
    {
        "ErrorEquals": [
            "Error"
        ],
        "Next": "Format Error Response",
    }
],
Enter fullscreen mode Exit fullscreen mode

Tanto el campo Catch como el Retry son arreglos de objetos, lo que permite el manejo de distintos tipos de errores.

Serverless

¿Qué es serverless? Es un modelo de ejecución, en el cual un proveedor de la nube (AWS, Google, o Azure) es responsable de ejecutar un fragmento de código mediante la asignación dinámica de los recursos. Y solo cobrando por la cantidad de recursos utilizados para ejecutar el código.

A la hora de trabajar con este modelo podemos recurrir a distintos frameworks. Uno de ellos es SAM(Serverless Application Model), el cual es un framework de código abierto creado para las arquitecturas serverless. Es el framework de AWS.
El framework que vamos a estar utilizando para crear nuestras máquinas de estados en esta serie va a ser Serverless Framework, el cual es un framework también de código abierto que fue el primero en ser creado para este tipo de arquitectura y es el más usado.

El modelo serverless también suele ser conocido como FaaS (Function as a Service).

Para su instalación necesitamos...

1 - Tener NodeJs instalado. (Instalar NodeJs https://nodejs.org/en/)
2 - Correr este comando en la consola (Docu instalación : https://www.serverless.com/framework/docs/getting-started)

npm install -g serverless
Enter fullscreen mode Exit fullscreen mode

Recomiendo tener esto instalado para el cuarto capítulo.

Fin

Este ha sido otro capítulo con material teórico.
En el próxima vamos a estar viendo un par de servicios de AWS que vamos a necesitar conocer para poder pasar luego a la creación de las máquinas de estado.

Para esto voy a necesitar que creen una cuenta en AWS, si es que no la tienen.

Se viene lo chido meme

Si el contenido les sirvió, no olviden que pueden invitarme un cafecito.

Invitame un café en cafecito.app

Nos vemos la próxima semana.

. . . . . . . . . . . . .