Migra de AWS Step Functions a Workflows

Ayudarte a prepararte para migrar de Step Functions de Amazon Web Services (AWS) a Workflows en Google Cloud; en esta página, se explican las similitudes clave y las diferencias entre ambos productos. Esta información tiene como fin ayudarte quienes ya están familiarizados con las funciones de pasos implementan un procedimiento similar arquitectura con Workflows.

Al igual que Step Functions, Workflows es un servicio completamente administrado, basado en de Google Cloud que ejecuta servicios en el orden que tú definas: un flujo de trabajo. Estos flujos de trabajo pueden combinar servicios, incluidos servicios personalizados alojados en Cloud Run o Cloud Run Functions, los servicios de Google Cloud como Cloud Vision AI y BigQuery, y cualquier API basada en HTTP.

Ten en cuenta que Step Functions Express Workflows es un flujo de trabajo de AWS Step Functions que no se considera aquí, ya que la duración de un flujo de trabajo exprés son limitadas y no se admite una ejecución de flujo de trabajo del tipo “exactamente una vez”.

Hello World

En Step Functions, una máquina de estados 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 cada estado defina el siguiente estado.

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

El siguiente mensaje "Hello World" El ejemplo muestra cómo usar estados en el Paso Funciones y pasos en Workflows:

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.

Step FunctionsWorkflows
SintaxisJSON (YAML en herramientas) YAML o JSON
Flujo de controlTransición entre estados Control de flujo imperativo con pasos
TrabajadorRecursos (ARN) Solicitudes y conectores HTTP
ConfiabilidadAtrapar/reintentar Captura o vuelve a intentarlo
ParalelismoAdmitido Admitido
Datos de estadoSe pasa el estado Variables de Workflows
AuthenticationIAM IAM
Experiencia del usuarioWorkflow Studio, CLI, SDK, IaC Consola de Google Cloud, CLI, SDK, IaC
Precios Precios de Step Functions Precios de Workflows
Sintaxis

Step Functions utiliza principalmente JSON para definir funciones y no es compatible 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 Step Functions.

Puedes describir los pasos de Workflows sintaxis y se pueden escribir en YAML o JSON. La mayoría de 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 Workflows, consulta el Referencia de la sintaxis.

Flujo de control

Tanto Workflows como Step Functions modelan flujos de trabajo como una serie de tareas: pasos en Workflows y estados en Step Functions. Ambos permiten que una tarea indique qué tarea ejecutar a continuación y admiten condicionales similares a interruptores para elegir la siguiente unidad de trabajo según el estado actual. Una llave La diferencia es que las funciones Step requieren que cada estado defina el siguiente, mientras que Workflows ejecuta los pasos en el orden en que son especificado (incluidos los pasos siguientes alternativos). Para obtener más información, consulta Condiciones y Pasos.

Trabajador

Ambos productos organizan recursos de procesamiento como las funciones, los contenedores y otros servicios web para completar tareas. En Step Functions, el trabajador se identifica con un campo Resource, que es un URI sintáctico. Los URI que se usan para identificar los recursos de trabajadores que están en formato Amazon Resource Name (ARN) y los usuarios no puede 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 APIs de Google Cloud dentro de un flujo de trabajo y la integración de tus flujos de trabajo con otros productos de Google Cloud, como Pub/Sub, BigQuery o Cloud Build. Los conectores simplifican los servicios de llamadas porque manejan el formato de las solicitudes por ti, proporcionan métodos y argumentos para que no necesites conocer los detalles de una API de Google Cloud. También puedes configurar las políticas de tiempo de espera y sondeo.

Confiabilidad

Si una tarea falla, tu flujo de trabajo debe poder reintentar de manera adecuada, detecta excepciones cuando sea necesario y redirigir el flujo de trabajo según sea necesario. Ambos pasos Functions y Workflows logran la confiabilidad con de detección de excepciones: captura de excepciones con reintentos y envío eventual a en otra parte del flujo de trabajo. Para obtener más información, consulta Errores de flujo de trabajo.

Paralelismo

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

En Workflows, puedes definir una parte de tu flujo de trabajo en la que dos o más pasos pueden ejecutarse simultáneamente. Puedes definir ramas que se ejecutan de forma simultánea o un bucle en el que las iteraciones se ejecutan de forma simultánea. Para obtener más información, consulta Cómo ejecutar pasos de flujo de trabajo en paralelo.

Datos de estado

Un beneficio de un motor de flujo de trabajo es que los datos de estado se mantienen por ti 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 formato global variables. Dado que tienes una duración de ejecución de hasta un año, puedes conservar los datos de estado, siempre y cuando la instancia siga en ejecución.

Autenticación

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

En Workflows, puedes usar una cuenta de servicio para invocar un workflow; puedes usar OAuth 2.0 u OIDC para conectarte con Google Cloud APIs; y puedes usar un encabezado de solicitud de autorización para autenticarte una API de terceros. Para obtener más información, consulta Otorga permiso a un flujo de trabajo para acceder a los recursos de Google Cloud y Realizar 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 Step Functions y Workflows.

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

Precios

Ambos productos tienen un nivel gratuito. Para obtener más detalles, consulta sus respectivas páginas de precios: Precios de Step Functions y Precios de Workflows.

Cómo asignar tipos de estado a pasos

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

Choice

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

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

Step Functions

  "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 estados y la marca como un error.

En Workflows, puedes generar errores personalizados con la sintaxis raise y detectar y controlar errores con un bloque try/except. Para 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 una entrada .

En Workflows, puedes usar bucles for para iteraciones.

Step Functions

  { "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 en paralelo.

En Workflows, puedes usar un paso parallel para definir una parte de tu flujo de trabajo en el que dos o más pasos pueden ejecutarse simultáneamente. Para obtener más información, consulta Pasos en 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

  main:
     params: [args]
     steps:
     - init:
         assign:
         - workflow_id: "lookupAddress"
         - customer_to_lookup:
             - address: ${args.customerId}
             - phone: ${args.customerId}
         - addressed: ["", ""] # to write to this variable, you must share it
     - parallel_address:
         parallel:
             shared: [addressed]
             for:
                 in: ${customer_to_lookup}
                 index: i # optional, use if index is required
                 value: arg
                 steps:
                 - address:
                     call: googleapis.workflowexecutions.v1.projects.locations.workflows.executions.run
                     args:
                         workflow_id: ${workflow_id}
                         argument: ${arg}
                     result: r
                 - set_result:
                     assign:
                     - addressed[i]: ${r}
     - return:
             return: ${addressed}

JSON de flujos de trabajo

  {
    "main": {
      "params": [
        "args"
      ],
      "steps": [
        {
          "init": {
            "assign": [
              {
                "workflow_id": "lookupAddress"
              },
              {
                "customer_to_lookup": [
                  {
                    "address": "${args.customerId}"
                  },
                  {
                    "phone": "${args.customerId}"
                  }
                ]
              },
              {
                "addressed": [
                  "",
                  ""
                ]
              }
            ]
          }
        },
        {
          "parallel_address": {
            "parallel": {
              "shared": [
                "addressed"
              ],
              "for": {
                "in": "${customer_to_lookup}",
                "index": "i",
                "value": "arg",
                "steps": [
                  {
                    "address": {
                      "call": "googleapis.workflowexecutions.v1.projects.locations.workflows.executions.run",
                      "args": {
                        "workflow_id": "${workflow_id}",
                        "argument": "${arg}"
                      },
                      "result": "r"
                    }
                  },
                  {
                    "set_result": {
                      "assign": [
                        {
                          "addressed[i]": "${r}"
                        }
                      ]
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "return": {
            "return": "${addressed}"
          }
        }
      ]
    }
  }

Pass

Un estado Pass pasa su entrada a su salida, sin realizar trabajo. Este es de uso general para manipular los datos de estado en JSON.

Como Workflows no pasa datos de esta manera, puedes dejar el estado como no operativo o usar un paso de asignación para modificar las variables. Para obtener más información, consulta Asigna variables.

Step Functions

  "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"
      }
    ]
  }

Lograr el éxito

Un estado Succeed detiene una ejecución correctamente.

En Workflows, 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 último paso (suponiendo que el paso no avanza 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 Completa la ejecución de un flujo de trabajo.

Step Functions

  "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 estados. En el siguiente ejemplo de Step Functions, se invoca una función Lambda. (Las actividades son una función de AWS Step Functions que te permite tener una tarea en tu máquina de estados en la que el trabajo se realiza en otro lugar).

En el ejemplo de Workflows, se hace una llamada a un extremo HTTP para invocar una función de Cloud Run. También puedes usar un conector que te permita acceder fácilmente a otros productos de Google Cloud. Además, puedes pausar un flujo de trabajo y sondear datos. O puedes usar un extremo de devolución de llamada para indicar al flujo de trabajo que se produjo un evento específico y esperar 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 continúe durante un tiempo específico.

Puedes usar la función de biblioteca estándar sys.sleep de Workflows para suspender la ejecución durante la cantidad de segundos determinada, hasta un máximo de 31536000 (un año).

Step Functions

  "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 Step Functions, se verifica el precio de una acción, se determina si se debe comprar o vender, y se informa el resultado. La máquina de estados del ejemplo se integra con AWS Lambda pasando parámetros, usa una cola de Amazon SQS para solicitar la aprobación humana 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
          }
      }
  }

Migra a Workflows

Para migrar el ejemplo anterior de Step Functions a Workflows, sigue estos pasos: puedes crear los pasos equivalentes de Workflows integrando Cloud Run Functions, que admiten un extremo de devolución de llamada que espera para que las solicitudes HTTP lleguen a ese extremo conector 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 implementas.

  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 Workflows 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 Pub/Sub. en este tema. Por ejemplo, my_stock_example
  3. Implementa y, luego, ejecuta el flujo de trabajo.

  4. Durante la ejecución del flujo de trabajo, este se detiene y espera a que invoques el elemento de devolución de llamada. Para ello, puedes usar un 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 las etiquetas. a tu extremo de devolución de llamada.

  5. Una vez que el flujo de trabajo se completó correctamente, puedes recibir el mensaje de la suscripción a 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?