Migra de las funciones de pasos de AWS a flujos de trabajo

En esta página, se explican las similitudes y diferencias clave entre los dos productos a fin de prepararte para migrar de las funciones de pasos de Amazon Web Services (AWS) a flujos de trabajo en Google Cloud. El objetivo de esta información es ayudar a quienes ya están familiarizados con Step Functions a implementar una arquitectura similar mediante flujos de trabajo.

Al igual que las funciones de pasos, los flujos de trabajo son una plataforma de organización basada en el estado completamente administrada que ejecuta servicios en el orden que definas: un flujo de trabajo. Estos flujos de trabajo pueden combinar servicios como servicios personalizados alojados en Cloud Run o Cloud Functions, servicios de Google Cloud, como Cloud Vision AI y BigQuery, y cualquier API basada en HTTP.

Ten en cuenta que los flujos de trabajo de Express de Step Functions son un tipo de flujo de trabajo de AWS Functions que no se consideran aquí, ya que la duración de un flujo de trabajo de Express es limitado y no se admite la ejecución de un flujo de trabajo exactamente una vez.

Hello World

En Step Functions, una máquina de estado es un flujo de trabajo, y una tarea es un estado en un flujo de trabajo que representa una sola unidad de trabajo que realiza otro servicio de AWS. Step Functions requiere que todos los estados definan el siguiente.

En Workflows, una serie de pasos que usan la sintaxis de flujos de trabajo describen las tareas que se deben ejecutar. Los flujos de trabajo tratan los pasos como si estuvieran en una lista ordenada y los ejecutan de a uno hasta que se hayan ejecutado todos.

En la siguiente muestra de “Hello World”, se usan los estados en las funciones de paso y los pasos de los flujos de trabajo:

Funciones de pasos

  {
    "Comment": "Hello world example of Pass states in Amazon States Language",
    "StartAt": "Hello",
    "States": {
      "Hello": {
        "Type": "Pass",
        "Result": "Hello",
        "Next": "World"
      },
      "World": {
        "Type": "Pass",
        "Result": "World",
        "End": true
      }
    }
  }

YAML de flujos de trabajo

  ---
  # Hello world example of steps using Google Cloud Workflows syntax
  main:
      steps:
      - Hello:
          next: World
      - World:
          next: end
  ...

JSON de flujos de trabajo

  {
    "main": {
      "steps": [
        {
          "Hello": {
            "next": "World"
          }
        },
        {
          "World": {
            "next": "end"
          }
        }
      ]
    }
  }

Descripción general de la comparación

En esta sección, se comparan los dos productos con más detalle.

Funciones de pasosWorkflows
SintaxisJSON (YAML en herramientas) YAML o JSON
Flujo de controlTransición entre estados Control de flujo imperativo con pasos
TrabajadorRecursos (ARN) Solicitudes HTTP y conectores
ConfiabilidadCapturar y reintentar Capturar y reintentar
ParalelismoAdmitido Disponible hasta el experimental.executions.map
Datos de estadoSe pasa el estado Variables de flujos de trabajo
AuthenticationIAM IAM
Experiencia del usuarioWorkflow Studio, CLI, SDK, IaC Google Cloud Console, CLI, SDK, IaC
Precios Precios de Step Functions Precios de flujos de trabajo
Sintaxis

Step Functions usa principalmente JSON para definir funciones y no admite YAML directamente; sin embargo, en el kit de herramientas de AWS para Visual Studio Code y en AWS CloudFormation, puedes usar YAML para una definición de funciones de paso.

Puedes describir los pasos de flujos de trabajo con la sintaxis de los flujos de trabajo, y puedes escribirlos en YAML o JSON. La mayoría de los flujos de trabajo están en YAML. En los ejemplos de esta página, se demuestran las ventajas de YAML, incluida la facilidad de lectura y escritura, y la compatibilidad nativa con los comentarios. Para obtener una explicación detallada de la sintaxis de los flujos de trabajo, consulta la Referencia de sintaxis.

Flujo de control

Tanto los flujos de trabajo como las funciones de paso modelan los flujos de trabajo como una serie de tareas: pasos en flujos de trabajo y estados en funciones de paso. Ambos permiten que una tarea indique cuál se ejecutará a continuación y admiten condicionales similares al interruptor para elegir la siguiente unidad de trabajo en función del estado actual. Una diferencia clave es que Step Functions requiere que todos los estados definan el siguiente, mientras que los flujos de trabajo ejecutan pasos en el orden en el que se especifican (incluidos los pasos siguientes alternativos). Para obtener más información, consulta Condiciones y Pasos.

de primera línea

Ambos productos organizan recursos de procesamiento, como funciones, contenedores y otros servicios web para completar tareas. En Step Functions, el trabajador se identifica mediante un campo Resource que es sintácticamente un URI. Los URI que se usan para identificar los recursos de trabajador están en formato Amazon Resource Name (ARN), y los usuarios no pueden invocar directamente un extremo HTTP arbitrario.

Los flujos de trabajo pueden enviar solicitudes HTTP a un extremo HTTP arbitrario y obtener una respuesta. Los conectores facilitan la conexión a otras API de Google Cloud dentro de un flujo de trabajo y la integración de tus flujos de trabajo a otros productos de Google Cloud, como Pub/Sub, BigQuery o Cloud Build. Los conectores simplifican los servicios de llamada porque controlan el formato de las solicitudes por ti, ya que proporcionan métodos y argumentos para que no necesites conocer los detalles de una API de Google Cloud. También puedes configurar el tiempo de espera y las políticas de sondeo.

Confiabilidad

Si una tarea falla, el flujo de trabajo debe poder volver a intentarlo de forma correcta, detectar excepciones cuando sea necesario y redireccionar el flujo de trabajo según sea necesario. Tanto las funciones de pasos como los flujos de trabajo logran la confiabilidad mediante mecanismos similares: captura de excepciones con reintentos y despacho eventual a otras partes del flujo de trabajo. Para obtener más información, consulta Errores del flujo de trabajo.

Paralelismo

Es posible que desees que tu flujo de trabajo organice varias tareas en paralelo. Step Functions proporciona dos maneras de lograr esto: puedes tomar un elemento de datos y pasarlo en paralelo a varias tareas diferentes o puedes usar un arreglo y pasar sus elementos a la misma tarea.

Puedes usar la función experimental de Workflows, experimental.executions.map, para admitir el trabajo paralelo.

Datos del estado

Un beneficio de un motor de flujo de trabajo es que los datos de estado se mantienen sin un almacén de datos externo. En Step Functions, los datos de estado se pasan en una estructura JSON de un estado a otro.

En Workflows, puedes guardar los datos de estado en variables globales. Dado que tienes una duración de ejecución de un año, puedes conservar los datos de estado siempre que la instancia aún esté en ejecución.

Autenticación

Ambos productos dependen de un sistema de administración de identidades y accesos (IAM) subyacente para la autenticación y el control de acceso. Por ejemplo, puedes usar una función de IAM para invocar funciones de pasos.

En Workflows, puedes usar una cuenta de servicio para invocar un flujo de trabajo, puedes usar OAuth 2.0 o OIDC para conectarte con las API de Google Cloud y puedes usar un encabezado de solicitud de autorización para autenticarte con una API de terceros. Si quieres obtener más información, consulta Otorga permiso a un flujo de trabajo para acceder a recursos de Google Cloud y Realiza solicitudes autenticadas desde un flujo de trabajo.

Experiencia del usuario

Puedes usar una herramienta de línea de comandos o una infraestructura como código (IaC), como Terraform, para definir y administrar las funciones de paso y los flujos de trabajo.

Además, los flujos de trabajo admiten la ejecución de flujos de trabajo mediante las bibliotecas cliente, en Cloud Console, con la CLI de Google Cloud o mediante el envío de una solicitud a la API de REST de flujos de trabajo. Para obtener más información, consulta Ejecuta un flujo de trabajo.

Precios

Ambos productos tienen un nivel gratuito. Para obtener más información, consulta las páginas de precios correspondientes: Precios de Step Functions y Precios de flujos de trabajo.

Asigna tipos de estado a pasos

Existen ocho tipos de estado en las funciones de pasos. Los estados son elementos de una máquina de estado que pueden tomar decisiones en función de sus entradas, realizar acciones y pasar resultados a otros estados. Antes de migrar de las funciones de paso a flujos de trabajo, asegúrate de comprender cómo traducir cada tipo de estado a un paso de flujos de trabajo.

Choice

Un estado Choice agrega una lógica de ramificación a una máquina de estado.

En Flujos de trabajo, puedes usar un bloque switch como mecanismo de selección que permita que el valor de una expresión controle el flujo de una ejecución de flujo de trabajo. Si un valor coincide, se ejecuta la instrucción de esa condición. Para obtener más información, consulta Condiciones.

Funciones de pasos

  "ChoiceState": {
    "Type": "Choice",
    "Choices": [
      {
        "Variable": "$.foo",
        "NumericEquals": 1,
        "Next": "FirstMatchState"
      },
      {
        "Variable": "$.foo",
        "NumericEquals": 2,
        "Next": "SecondMatchState"
      }
    ],
    "Default": "DefaultState"
  }

YAML de flujos de trabajo

  switch:
    - condition: ${result.body.SomeField < 10}
      next: small
    - condition: ${result.body.SomeField < 100}
      next: medium
    - condition: true
      next: default_step

JSON de flujos de trabajo

  {
    "switch": [
      {
        "condition": "${result.body.SomeField < 10}",
        "next": "small"
      },
      {
        "condition": "${result.body.SomeField < 100}",
        "next": "medium"
      },
      {
        "condition": true,
        "next": "default_step"
      }
    ]
  }

Fail

Un estado Fail detiene la ejecución de la máquina de estado y lo marca como un error.

En Workflows, puedes generar errores personalizados con la sintaxis raise y puedes detectar y resolver errores mediante un bloque try/except. Para obtener más información, consulta Cómo generar errores.

Funciones de pasos

  "FailState": {
      "Type": "Fail",
      "Error": "ErrorA",
      "Cause": "Kaiju attack"
  }

YAML de flujos de trabajo

  raise:
      code: 55
      message: "Something went wrong."

JSON de flujos de trabajo

  {
    "raise": {
      "code": 55,
      "message": "Something went wrong."
    }
  }

Map

Se puede usar un estado Map a fin de ejecutar un conjunto de pasos para cada elemento de un arreglo de entrada.

En Flujos de trabajo, puedes usar bucles for para las iteraciones.

Funciones de pasos

  { "StartAt": "ExampleMapState",
    "States": {
      "ExampleMapState": {
        "Type": "Map",
        "Iterator": {
           "StartAt": "CallLambda",
           "States": {
             "CallLambda": {
               "Type": "Task",
               "Resource": "arn:aws:lambda:us-east-1:123456789012:function:HelloFunction",
               "End": true
             }
           }
        }, "End": true
      }
    }
  }

YAML de flujos de trabajo

  - assignStep:
      assign:
        - map:
            1: 10
            2: 20
            3: 30
        - sum: 0
  - loopStep:
      for:
          value: key
          in: ${keys(map)}
          steps:
            - sumStep:
                assign:
                  - sum: ${sum + map[key]}
  - returnStep:
      return: ${sum}

JSON de flujos de trabajo

  [
    {
      "assignStep": {
        "assign": [
          {
            "map": {
              "1": 10,
              "2": 20,
              "3": 30
            }
          },
          {
            "sum": 0
          }
        ]
      }
    },
    {
      "loopStep": {
        "for": {
          "value": "key",
          "in": "${keys(map)}",
          "steps": [
            {
              "sumStep": {
                "assign": [
                  {
                    "sum": "${sum + map[key]}"
                  }
                ]
              }
            }
          ]
        }
      }
    },
    {
      "returnStep": {
        "return": "${sum}"
      }
    }
  ]

Parallel

Se puede usar un estado Parallel para crear ramas paralelas de ejecución en tu máquina de estado. En el siguiente ejemplo de Step Functions, se realiza una búsqueda de dirección y teléfono de manera paralela.

En Workflows, puedes usar una función experimental, experimental.executions.map, para admitir el trabajo paralelo.

Funciones de pasos

  { "StartAt": "LookupCustomerInfo",
    "States": {
      "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
             }
           }
         }
        ]
      }
    }
  }

YAML de flujos de trabajo

  - parallel-executor:
      call: experimental.executions.map
      args:
        workflow_id: LookupCustomerInfo
        arguments: [{"LookupAddress":"${cust_id}"},{"LookupPhone":"${cust_id}"}]
      result: result

JSON de flujos de trabajo

  [
    {
      "parallel-executor": {
        "call": "experimental.executions.map",
        "args": {
          "workflow_id": "LookupCustomerInfo",
          "arguments": [
            {
              "LookupAddress": "${cust_id}"
            },
            {
              "LookupPhone": "${cust_id}"
            }
          ]
        },
        "result": "result"
      }
    }
  ]

Pass

Un estado Pass pasa su entrada a su salida, sin realizar el trabajo. Por lo general, se usa para manipular los datos de estado del archivo JSON.

Como los flujos de trabajo no pasan datos de esta manera, puedes dejar el estado como no-op o puedes usar un paso de asignación para modificar las variables. Para obtener más información, consulta Cómo asignar variables.

Funciones de pasos

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

YAML de flujos de trabajo

  assign:
      - number: 5
      - number_plus_one: ${number+1}
      - other_number: 10
      - string: "hello"

JSON de flujos de trabajo

  {
    "assign": [
      {
        "number": 5
      },
      {
        "number_plus_one": "${number+1}"
      },
      {
        "other_number": 10
      },
      {
        "string": "hello"
      }
    ]
  }

Correcto

El estado Succeed detiene una ejecución correctamente.

En Flujos de trabajo, puedes usar return en el flujo de trabajo principal para detener la ejecución de un flujo de trabajo. También puedes finalizar un flujo de trabajo completando el paso final (suponiendo que el paso no pasa a otro) o puedes usar next: end para detener la ejecución de un flujo de trabajo si no necesitas mostrar un valor. Para obtener más información, consulta Cómo completar la ejecución de un flujo de trabajo.

Funciones de pasos

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

YAML de flujos de trabajo

  return: "Success!"
  next: end

JSON de flujos de trabajo

  {
    "return": "Success!",
    "next": "end"
  }

Task

Un estado Task representa una sola unidad de trabajo que realiza una máquina de estado. En el siguiente ejemplo de funciones de pasos, invoca una función lambda. (Las actividades son una función de los pasos de AWS que te permiten realizar una tarea en tu máquina de estado en la que el trabajo se realiza en otro lugar).

En el ejemplo de flujos de trabajo, se realiza una llamada a un extremo HTTP para invocar una función de Cloud Functions. También puedes usar un conector que permita un acceso fácil a otros productos de Google Cloud. Además, puedes pausar el flujo de trabajo y sondear los datos. También puedes usar un extremo de devolución de llamada para indicar a tu flujo de trabajo que se produjo un evento específico y esperar a que se ejecute ese evento sin sondeo.

Funciones de pasos

  "HelloWorld": {
    "Type": "Task",
    "Resource": "arn:aws:lambda:us-east-1:123456789012:function:HelloFunction",
    "End": true
  }

YAML de flujos de trabajo

  - HelloWorld:
      call: http.get
      args:
          url: https://REGION-PROJECT_ID.cloudfunctions.net/helloworld
      result: helloworld_result

JSON de flujos de trabajo

  [
    {
      "HelloWorld": {
        "call": "http.get",
        "args": {
          "url": "https://REGION-PROJECT_ID.cloudfunctions.net/helloworld"
        },
        "result": "helloworld_result"
      }
    }
  ]

Wait

Un estado Wait retrasa la máquina de estado para que no se conserve durante un tiempo específico.

Puedes usar la sys.sleep función de biblioteca estándar de flujos de trabajo para suspender la ejecución de la cantidad de segundos especificada a un máximo de 31536000 (un año).

Funciones de pasos

  "wait_ten_seconds" : {
    "Type" : "Wait",
    "Seconds" : 10,
    "Next": "NextState"
  }

YAML de flujos de trabajo

  - someSleep:
      call: sys.sleep
      args:
          seconds: 10

JSON de flujos de trabajo

  [
    {
      "someSleep": {
        "call": "sys.sleep",
        "args": {
          "seconds": 10
        }
      }
    }
  ]

Ejemplo: Organiza microservicios

En el siguiente ejemplo de funciones de pasos, se verifica el precio de una acción, se determina si se compra o se vende, y se informa el resultado. La máquina de estado de la muestra se integra en AWS Lambda pasando parámetros, usa una cola de Amazon SQS para solicitar la aprobación manual y usa un tema de Amazon SNS para mostrar los resultados de la consulta.

{
      "StartAt": "Check Stock Price",
      "Comment": "An example of integrating Lambda functions in Step Functions state machine",
      "States": {
          "Check Stock Price": {
              "Type": "Task",
              "Resource": "CHECK_STOCK_PRICE_LAMBDA_ARN",
              "Next": "Generate Buy/Sell recommendation"
          },
          "Generate Buy/Sell recommendation": {
              "Type": "Task",
              "Resource": "GENERATE_BUY_SELL_RECOMMENDATION_LAMBDA_ARN",
              "ResultPath": "$.recommended_type",
              "Next": "Request Human Approval"
          },
          "Request Human Approval": {
              "Type": "Task",
              "Resource": "arn:PARTITION:states:::sqs:sendMessage.waitForTaskToken",
              "Parameters": {
                  "QueueUrl": "REQUEST_HUMAN_APPROVAL_SQS_URL",
                  "MessageBody": {
                      "Input.$": "$",
                      "TaskToken.$": "$$.Task.Token"
                  }
              },
              "ResultPath": null,
              "Next": "Buy or Sell?"
          },
          "Buy or Sell?": {
              "Type": "Choice",
              "Choices": [
                  {
                      "Variable": "$.recommended_type",
                      "StringEquals": "buy",
                      "Next": "Buy Stock"
                  },
                  {
                      "Variable": "$.recommended_type",
                      "StringEquals": "sell",
                      "Next": "Sell Stock"
                  }
              ]
          },
          "Buy Stock": {
              "Type": "Task",
              "Resource": "BUY_STOCK_LAMBDA_ARN",
              "Next": "Report Result"
          },
          "Sell Stock": {
              "Type": "Task",
              "Resource": "SELL_STOCK_LAMBDA_ARN",
              "Next": "Report Result"
          },
          "Report Result": {
              "Type": "Task",
              "Resource": "arn:PARTITION:states:::sns:publish",
              "Parameters": {
                  "TopicArn": "REPORT_RESULT_SNS_TOPIC_ARN",
                  "Message": {
                      "Input.$": "$"
                  }
              },
              "End": true
          }
      }
  }

Cómo migrar a flujos de trabajo

Para migrar el ejemplo anterior de las funciones de los pasos a flujos de trabajo, puedes crear los pasos equivalentes de flujos de trabajo si integras Cloud Functions, admites un extremo de devolución de llamada que espera que las solicitudes HTTP lleguen a ese extremo y usas un conector de flujos de trabajo para publicar en un tema de Pub/Sub en lugar del tema de Amazon SNS:

  1. Completa los pasos para crear un flujo de trabajo, pero aún no lo implementes.

  2. En la definición del flujo de trabajo, agrega un paso para crear un extremo de devolución de llamada que espere una entrada humana, y un paso que use un conector de flujos de trabajo para publicar en un tema de Pub/Sub. Por ejemplo:

    YAML de flujos de trabajo

      ---
      main:
        steps:
          - init:
              assign:
                - projectId: '${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}'
                - region: LOCATION
                - topic: PUBSUB_TOPIC_NAME
          - Check Stock Price:
              call: http.get
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/CheckStockPrice"}
                auth:
                  type: OIDC
              result: stockPriceResponse
          - Generate Buy/Sell Recommendation:
              call: http.get
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/BuySellRecommend"}
                auth:
                  type: OIDC
                query:
                  price: ${stockPriceResponse.body.stock_price}
              result: recommendResponse
          - Create Approval Callback:
              call: events.create_callback_endpoint
              args:
                  http_callback_method: "GET"
              result: callback_details
          - Print Approval Callback Details:
              call: sys.log
              args:
                  severity: "INFO"
                  text: ${"Listening for callbacks on " + callback_details.url}
          - Await Approval Callback:
              call: events.await_callback
              args:
                  callback: ${callback_details}
                  timeout: 3600
              result: approvalResponse
          - Approval?:
              try:
                switch:
                  - condition: ${approvalResponse.http_request.query.response[0] == "yes"}
                    next: Buy or Sell?
              except:
                as: e
                steps:
                  - unknown_response:
                      raise: ${"Unknown response:" + e.message}
                      next: end
          - Buy or Sell?:
              switch:
                - condition: ${recommendResponse.body == "buy"}
                  next: Buy Stock
                - condition: ${recommendResponse.body == "sell"}
                  next: Sell Stock
                - condition: true
                  raise: ${"Unknown recommendation:" + recommendResponse.body}
          - Buy Stock:
              call: http.post
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/BuyStock"}
                auth:
                  type: OIDC
                body:
                  action: ${recommendResponse.body}
              result: message
          - Sell Stock:
              call: http.post
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/SellStock"}
                auth:
                  type: OIDC
                body:
                  action: ${recommendResponse.body}
              result: message
          - Report Result:
              call: googleapis.pubsub.v1.projects.topics.publish
              args:
                topic: ${"projects/" + projectId + "/topics/" + topic}
                body:
                  messages:
                  - data: '${base64.encode(json.encode(message))}'
              next: end
      ...

    JSON de flujos de trabajo

      {
        "main": {
          "steps": [
            {
              "init": {
                "assign": [
                  {
                    "projectId": "${sys.get_env(\"GOOGLE_CLOUD_PROJECT_ID\")}"
                  },
                  {
                    "region": "LOCATION"
                  },
                  {
                    "topic": [
                      "PUBSUB_TOPIC_NAME"
                    ]
                  }
                ]
              }
            },
            {
              "Check Stock Price": {
                "call": "http.get",
                "args": {
                  "url": "${\"https://\" + region + \"-\" + projectId + \".cloudfunctions.net/CheckStockPrice\"}",
                  "auth": {
                    "type": "OIDC"
                  }
                },
                "result": "stockPriceResponse"
              }
            },
            {
              "Generate Buy/Sell Recommendation": {
                "call": "http.get",
                "args": {
                  "url": "${\"https://\" + region + \"-\" + projectId + \".cloudfunctions.net/BuySellRecommend\"}",
                  "auth": {
                    "type": "OIDC"
                  },
                  "query": {
                    "price": "${stockPriceResponse.body.stock_price}"
                  }
                },
                "result": "recommendResponse"
              }
            },
            {
              "Create Approval Callback": {
                "call": "events.create_callback_endpoint",
                "args": {
                  "http_callback_method": "GET"
                },
                "result": "callback_details"
              }
            },
            {
              "Print Approval Callback Details": {
                "call": "sys.log",
                "args": {
                  "severity": "INFO",
                  "text": "${\"Listening for callbacks on \" + callback_details.url}"
                }
              }
            },
            {
              "Await Approval Callback": {
                "call": "events.await_callback",
                "args": {
                  "callback": "${callback_details}",
                  "timeout": 3600
                },
                "result": "approvalResponse"
              }
            },
            {
              "Approval?": {
                "try": {
                  "switch": [
                    {
                      "condition": "${approvalResponse.http_request.query.response[0] == \"yes\"}",
                      "next": "Buy or Sell?"
                    }
                  ]
                },
                "except": {
                  "as": "e",
                  "steps": [
                    {
                      "unknown_response": {
                        "raise": "${\"Unknown response:\" + e.message}",
                        "next": "end"
                      }
                    }
                  ]
                }
              }
            },
            {
              "Buy or Sell?": {
                "switch": [
                  {
                    "condition": "${recommendResponse.body == \"buy\"}",
                    "next": "Buy Stock"
                  },
                  {
                    "condition": "${recommendResponse.body == \"sell\"}",
                    "next": "Sell Stock"
                  },
                  {
                    "condition": true,
                    "raise": "${\"Unknown recommendation:\" + recommendResponse.body}"
                  }
                ]
              }
            },
            {
              "Buy Stock": {
                "call": "http.post",
                "args": {
                  "url": "${\"https://\" + region + \"-\" + projectId + \".cloudfunctions.net/BuyStock\"}",
                  "auth": {
                    "type": "OIDC"
                  },
                  "body": {
                    "action": "${recommendResponse.body}"
                  }
                },
                "result": "message"
              }
            },
            {
              "Sell Stock": {
                "call": "http.post",
                "args": {
                  "url": "${\"https://\" + region + \"-\" + projectId + \".cloudfunctions.net/SellStock\"}",
                  "auth": {
                    "type": "OIDC"
                  },
                  "body": {
                    "action": "${recommendResponse.body}"
                  }
                },
                "result": "message"
              }
            },
            {
              "Report Result": {
                "call": "googleapis.pubsub.v1.projects.topics.publish",
                "args": {
                  "topic": "${\"projects/\" + projectId + \"/topics/\" + topic}",
                  "body": {
                    "messages": [
                      {
                        "data": "${base64.encode(json.encode(message))}"
                      }
                    ]
                  }
                },
                "next": "end"
              }
            }
          ]
        }
      }

    Reemplaza lo siguiente:

    • LOCATION: Es una región de Google Cloud compatible. Por ejemplo, us-central1.
    • PUBSUB_TOPIC_NAME: Es el nombre de tu tema de Pub/Sub. Por ejemplo, my_stock_example.
  3. Implementa y, luego, ejecuta el flujo de trabajo.

  4. Durante la ejecución del flujo de trabajo, se detiene y espera a que invoques el extremo de devolución de llamada. Para ello, pueden usar el comando curl. Por ejemplo:

    curl -H "Authorization: Bearer $(gcloud auth print-access-token)"
    https://workflowexecutions.googleapis.com/v1/projects/CALLBACK_URL?response=yes
    

    Reemplaza CALLBACK_URL por el resto de la ruta de acceso a tu extremo de devolución de llamada.

  5. Una vez que se complete correctamente el flujo de trabajo, podrás recibir el mensaje desde la suscripción de Pub/Sub. Por ejemplo:

    gcloud pubsub subscriptions pull stock_example-sub  --format="value(message.data)" | jq
    

    El mensaje de salida debería ser similar al siguiente (ya sea un buy o un sell):

    {
      "body": "buy",
      "code": 200,
      "headers": {
      [...]
      }
    

¿Qué sigue?