Migrar de AWS Step Functions a Workflows

Para 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 principales similitudes y diferencias entre los dos productos. Esta información está dirigida a los usuarios que ya conocen Step Functions y quieren implementar una arquitectura similar con Workflows.

Al igual que Step Functions, Workflows es una plataforma de orquestación totalmente gestionada y basada en estados que ejecuta servicios en el orden que definas: un flujo de trabajo. Estos flujos de trabajo pueden combinar servicios, incluidos servicios personalizados alojados en Cloud Run o funciones de Cloud Run, Google Cloud servicios como Cloud Vision AI y BigQuery, y cualquier API basada en HTTP.

Ten en cuenta que Workflows Exprés de Step Functions es un tipo de workflow de AWS Step Functions que no se tiene en cuenta aquí, ya que la duración de un workflow exprés es limitada y no se admite la ejecución de workflows exactamente una vez.

Primeros pasos

En Step Functions, una máquina de estados es un flujo de trabajo y una tarea es un estado de 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 que usan 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 uno hasta que se hayan completado todos.

En el siguiente ejemplo de "Hello world" se muestra el uso de estados en Step Functions y pasos en Workflows:

Funciones escalonadas

  {
    "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 escalonadasFlujos de trabajo
SintaxisJSON (YAML en las herramientas) YAML o JSON
Flujo de controlTransición entre estados Control de flujo imperativo con pasos
TrabajadorRecursos (ARN) y tarea HTTP Solicitudes HTTP y conectores
FiabilidadCaptura o reintento Captura o reintento
ParalelismoCompatible Compatible
Datos de estadoEl estado se transfiere Variables de flujo de trabajo
AutenticaciónGestión de identidades y accesos Gestión de identidades y accesos
Experiencia de usuarioWorkflow Studio, CLI, SDK e IaC Google Cloud Consola, CLI, SDK e IaC
Precios Precios de Step Functions Precios de Workflows
Sintaxis

Step Functions usa principalmente JSON para definir funciones y no admite YAML directamente. Sin embargo, en AWS Toolkit for Visual Studio Code y en AWS CloudFormation, puedes usar YAML para definir Step Functions.

Puedes describir los pasos de Workflows con la sintaxis de Workflows, que se puede escribir en YAML o JSON. La mayoría de los flujos de trabajo están en YAML. Los ejemplos de esta página muestran las ventajas de YAML, como 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 la referencia de sintaxis.

Flujo de control

Tanto Workflows como Step Functions modelan los flujos de trabajo como una serie de tareas: pasos en Workflows y estados en Step Functions. Ambos permiten que una tarea indique qué tarea se debe ejecutar a continuación y admiten condicionales similares a los de un interruptor para elegir la siguiente unidad de trabajo en función del estado actual. Una diferencia clave es que Step Functions requiere que cada estado defina el siguiente, mientras que Workflows ejecuta los pasos en el orden en el que se especifican (incluidos los pasos siguientes alternativos). Para obtener más información, consulta las condiciones y los pasos.

Trabajador

Ambos productos organizan recursos de computación, como funciones, contenedores y otros servicios web, para llevar a cabo tareas. En Step Functions, el trabajador se identifica mediante un campo Resource que es sintácticamente un URI. Los URIs que se usan para identificar los recursos de los trabajadores tienen el formato de nombre de recurso de Amazon (ARN). Para invocar directamente un endpoint HTTP arbitrario, puedes definir una tarea HTTP.

Los flujos de trabajo pueden enviar solicitudes HTTP a un endpoint HTTP arbitrario y obtener una respuesta. Los conectores facilitan la conexión a otras Google Cloud APIs 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 las llamadas a servicios, ya que se encargan de dar formato a las solicitudes por ti. Además, proporcionan métodos y argumentos para que no tengas que conocer los detalles de una API deGoogle Cloud . También puedes configurar las políticas de tiempo de espera y de sondeo.

Fiabilidad

Si una tarea falla, tu flujo de trabajo debe poder reintentarse de forma adecuada, detectar excepciones cuando sea necesario y redirigir el flujo de trabajo según sea necesario. Tanto Step Functions como Workflows consiguen fiabilidad mediante mecanismos similares: captura de excepciones con reintentos y envío final a otra parte del flujo de trabajo. Para obtener más información, consulta Errores de flujo de trabajo.

Paralelismo

Es posible que quieras que tu flujo de trabajo coordine varias tareas en paralelo. Step Functions ofrece dos formas de hacerlo: puedes tomar un elemento de datos y pasarlo en paralelo a varias tareas diferentes, o bien puedes usar una matriz y pasar sus elementos a la misma tarea.

En Workflows, puedes definir una parte de tu flujo de trabajo en la que se puedan ejecutar dos o más pasos simultáneamente. Puedes definir ramas que se ejecuten simultáneamente o un bucle en el que las iteraciones se ejecuten simultáneamente. Para obtener más información, consulta Ejecutar pasos de un flujo de trabajo en paralelo.

Datos de estado

Una de las ventajas de un motor de flujo de trabajo es que los datos de estado se mantienen sin necesidad de un almacén de datos externo. En Step Functions, los datos de estado se transfieren en una estructura JSON de un estado a otro.

En Workflows, puedes guardar los datos de estado en variables globales. Como tienes permitido un tiempo de ejecución de hasta un año, puedes conservar los datos de estado mientras la instancia siga en ejecución.

Autenticación

Ambos productos se basan en un sistema de gestión de identidades y accesos (IAM) subyacente para la autenticación y el control de acceso. Por ejemplo, puedes usar un rol de gestión de identidades y accesos para invocar Step Functions.

En Workflows, puedes usar una cuenta de servicio para invocar un flujo de trabajo, usar OAuth 2.0 u OIDC para conectarte con APIs de Google Cloudy usar un encabezado de solicitud de autorización para autenticarte con una API de terceros. Para obtener más información, consulta los artículos Conceder permiso a un flujo de trabajo para acceder a recursos Google Cloud y Hacer solicitudes autenticadas desde un flujo de trabajo.

Experiencia de usuario

Puedes usar una herramienta de línea de comandos o una infraestructura como código (IaC), como Terraform, para definir y gestionar tanto Step Functions como Workflows.

Además, Workflows admite la ejecución de flujos de trabajo mediante las bibliotecas de cliente, en la Google Cloud consola, con la CLI de Google Cloud o enviando una solicitud a la API REST de Workflows. Para obtener más información, consulta Ejecutar 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 Workflows.

Asignar tipos de estado a pasos

Hay 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 enviar salidas a otros estados. Antes de migrar de Step Functions a Workflows, asegúrate de saber cómo traducir cada tipo de estado a un paso de Workflows.

Choice

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

En Workflows, puedes usar un bloque switch como mecanismo de selección que permita que el valor de una expresión controle el flujo de 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.

Funciones escalonadas

  "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 puedes detectar y gestionar errores con un bloque try/except. Para obtener más información, consulta Generar errores.

Funciones escalonadas

  "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 para ejecutar un conjunto de pasos para cada elemento de una matriz de entrada.

En Workflows, puedes usar bucles for para iteraciones.

Funciones escalonadas

  { "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 de ejecución paralelas en tu máquina de estados. 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 la que se pueden ejecutar dos o más pasos simultáneamente. Para obtener más información, consulta Pasos paralelos.

Funciones escalonadas

  { "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 Pass pasa su entrada a su salida sin realizar ningún trabajo. Se suele usar para manipular los datos de estado en el JSON.

Como Workflows no transfiere datos de esta forma, puedes dejar el estado como una operación nula o usar un paso de asignación para modificar las variables. Para obtener más información, consulta Asignar variables.

Funciones escalonadas

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

Completada

El 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 paso final (siempre que no se salte a otro) o usar next: end para detener la ejecución de un flujo de trabajo si no necesitas devolver ningún valor. Para obtener más información, consulta Completar la ejecución de un flujo de trabajo.

Funciones escalonadas

  "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 realizada por 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 llama a un endpoint HTTP para invocar una función de Cloud Run. También puedes usar un conector que te permita acceder fácilmente a otros Google Cloud productos. Además, puedes pausar un flujo de trabajo y sondear los datos. También puedes usar un endpoint de retrollamada para indicar a tu flujo de trabajo que se ha producido un evento específico y esperar a que se produzca ese evento sin sondeo.

Funciones escalonadas

  "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 continuación de la máquina de estados durante un tiempo especificado.

Puedes usar la función de biblioteca estándar de Workflows sys.sleep para suspender la ejecución durante el número de segundos indicado, hasta un máximo de 31.536.000 (un año).

Funciones escalonadas

  "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: orquestar microservicios

En el siguiente ejemplo de Step Functions se comprueba el precio de las acciones, se determina si se deben comprar o vender y se informa del resultado. La máquina de estados del ejemplo se integra con AWS Lambda transfiriendo parámetros, usa una cola de Amazon SQS para solicitar la aprobación humana y usa un tema de Amazon SNS para devolver 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
          }
      }
  }

Migrar a Workflows

Para migrar el ejemplo anterior de Step Functions a Workflows, puedes crear los pasos equivalentes de Workflows integrando funciones de Cloud Run, que admiten un endpoint de retrollamada que espera a que lleguen solicitudes HTTP a ese endpoint, y usando un conector de Workflows para publicar en un tema de Pub/Sub en lugar del tema de Amazon SNS:

  1. Sigue los pasos para crear un flujo de trabajo, pero no lo implementes todavía.

  2. En la definición del flujo de trabajo, añade un paso para crear un endpoint de retrollamada que espere la 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"
              }
            }
          ]
        }
      }

    Haz los cambios siguientes:

    • LOCATION: una Google Cloud región admitida. Por ejemplo, us-central1.
    • PUBSUB_TOPIC_NAME: el nombre de tu tema de Pub/Sub. Por ejemplo, my_stock_example.
  3. Despliega y, a continuación, ejecuta el flujo de trabajo.

  4. Durante la ejecución del flujo de trabajo, se detiene y espera a que invoques el endpoint 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
    

    Sustituye CALLBACK_URL por el resto de la ruta a tu endpoint de retrollamada.

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

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

    El mensaje de salida debe ser similar al siguiente (buy o sell):

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

Siguientes pasos