Migre do AWS Step Functions para o Workflows

Para ajudar a preparar a migração das funções de passo dos Amazon Web Services (AWS) para os fluxos de trabalho no Google Cloud, esta página explica as principais semelhanças e diferenças entre os dois produtos. Estas informações destinam-se a ajudar as pessoas que já estão familiarizadas com as Step Functions a implementar uma arquitetura semelhante através dos Workflows.

Tal como as Step Functions, os Workflows são uma plataforma de orquestração totalmente gerida baseada em estados que executa serviços por si definidos: um fluxo de trabalho. Estes fluxos de trabalho podem combinar serviços, incluindo serviços personalizados alojados no Cloud Run ou nas funções do Cloud Run, Google Cloud serviços como a Cloud Vision AI e o BigQuery, e qualquer API baseada em HTTP.

Tenha em atenção que os fluxos de trabalho rápidos do Step Functions são um tipo de fluxo de trabalho do AWS Step Functions que não é considerado aqui, uma vez que a duração de um fluxo de trabalho rápido é limitada e não é suportada uma execução de fluxo de trabalho exatamente uma vez.

Olá, mundo

Nas Step Functions, uma máquina de estados é um fluxo de trabalho e uma tarefa é um estado num fluxo de trabalho que representa uma única unidade de trabalho que outro serviço da AWS executa. O Step Functions requer que cada estado defina o estado seguinte.

Nos fluxos de trabalho, uma série de passos que usam a sintaxe dos fluxos de trabalho descreve as tarefas a executar. Os fluxos de trabalho tratam os passos como se estivessem numa lista ordenada e executam-nos um de cada vez até que todos os passos tenham sido executados.

O seguinte exemplo "Olá, mundo" demonstra a utilização de estados em Step Functions e passos em fluxos de trabalho:

Funções 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 dos workflows

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

JSON de fluxos de trabalho

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

Vista geral da comparação

Esta secção compara os dois produtos mais detalhadamente.

Funções escalonadasWorkflows
SintaxeJSON (YAML nas ferramentas) YAML ou JSON
Fluxo de controloTransição entre estados Controlo de fluxo imperativo com passos
TrabalhadorRecursos (ARN) e tarefa HTTP Pedidos HTTP e conetores
FiabilidadeCapturar/tentar novamente Capturar/tentar novamente
ParalelismoSuportado Suportado
Dados de estadoO estado é transmitido Variáveis do Workflows
AutenticaçãoIAM IAM
Experiência do utilizadorWorkflow Studio, CLI, SDK e IaC Google Cloud consola, CLI, SDK, IaC
Preços Preços das Step Functions Preços dos fluxos de trabalho
Sintaxe

O Step Functions usa principalmente JSON para definir funções e não suporta YAML diretamente. No entanto, no AWS Toolkit for Visual Studio Code e no AWS CloudFormation, pode usar YAML para uma definição do Step Functions.

Pode descrever os passos dos fluxos de trabalho através da sintaxe Workflows e podem ser escritos em YAML ou JSON. A maioria dos fluxos de trabalho está em YAML. Os exemplos nesta página demonstram as vantagens do YAML, incluindo a facilidade de leitura e escrita, e o suporte nativo de comentários. Para uma explicação detalhada da sintaxe dos fluxos de trabalho, consulte a Referência de sintaxe.

Fluxo de controlo

Os fluxos de trabalho e as funções de passo modelam os fluxos de trabalho como uma série de tarefas: passos nos fluxos de trabalho e estados nas funções de passo. Ambos permitem que uma tarefa indique qual a tarefa a executar a seguir e suportam condições semelhantes a comutadores para escolher a próxima unidade de trabalho com base no estado atual. Uma diferença fundamental é que as Step Functions exigem que cada estado defina o seguinte, enquanto os fluxos de trabalho executam os passos pela ordem em que são especificados (incluindo passos seguintes alternativos). Para mais informações, consulte as Condições e os Passos.

Worker

Ambos os produtos orquestram recursos de computação, como funções, contentores e outros serviços Web, para realizar tarefas. Nas Step Functions, o trabalhador é identificado por um campo Resource que é sintaticamente um URI. Os URIs usados para identificar recursos de trabalhadores estão no formato de nome de recurso da Amazon (ARN). Para invocar diretamente um ponto final HTTP arbitrário, pode definir uma tarefa HTTP.

Os fluxos de trabalho podem enviar pedidos HTTP para um ponto final HTTP arbitrário e receber uma resposta. Os conetores facilitam a ligação a outras Google Cloud APIs num fluxo de trabalho e a integração dos seus fluxos de trabalho com outros Google Cloud produtos, como o Pub/Sub, o BigQuery ou o Cloud Build. Os conetores simplificam os serviços de chamadas porque processam a formatação dos pedidos por si, fornecendo métodos e argumentos para que não precise de saber os detalhes de umaGoogle Cloud API. Também pode configurar as políticas de tempo limite e de sondagem.

Fiabilidade

Se uma tarefa falhar, o fluxo de trabalho tem de conseguir repetir a tarefa de forma adequada, captar exceções quando for necessário e reencaminhar o fluxo de trabalho conforme necessário. As Step Functions e os fluxos de trabalho alcançam a fiabilidade através de mecanismos semelhantes: captura de exceções com novas tentativas e envio final para outro local no fluxo de trabalho. Para mais informações, consulte o artigo Erros de fluxo de trabalho.

Paralelismo

Pode querer que o fluxo de trabalho orquestre várias tarefas em paralelo. As funções de passos oferecem duas formas de o fazer: pode usar um item de dados e transmiti-lo em paralelo a várias tarefas diferentes ou pode usar uma matriz e transmitir os respetivos elementos à mesma tarefa.

Nos fluxos de trabalho, pode definir uma parte do fluxo de trabalho em que dois ou mais passos podem ser executados em simultâneo. Pode definir ramificações que são executadas em simultâneo ou um ciclo em que as iterações são executadas em simultâneo. Para obter detalhes, consulte o artigo Execute passos do fluxo de trabalho em paralelo.

Dados estatais

Uma vantagem de um motor de fluxo de trabalho é que os dados de estado são mantidos para si sem um armazenamento de dados externo. Nas Step Functions, os dados de estado são transmitidos numa estrutura JSON de um estado para outro.

Nos fluxos de trabalho, pode guardar os dados de estado em variáveis globais. Uma vez que são permitidos até um ano de duração da execução, pode manter os dados de estado enquanto a instância ainda estiver em execução.

Autenticação

Ambos os produtos baseiam-se num sistema de gestão de identidade e de acesso (IAM) subjacente para autenticação e controlo de acesso. Por exemplo, pode usar uma função do IAM para invocar Step Functions.

Nos fluxos de trabalho, pode usar uma conta de serviço para invocar um fluxo de trabalho; pode usar o OAuth 2.0 ou o OIDC para estabelecer ligação com as APIs; e pode usar um cabeçalho de pedido de autorização para autenticar com uma API de terceiros. Google CloudPara mais informações, consulte os artigos Conceda uma autorização de fluxo de trabalho para aceder a Google Cloud recursos e Faça pedidos autenticados a partir de um fluxo de trabalho.

Experiência do utilizador

Pode usar uma ferramenta de linha de comandos ou infraestrutura como código (IaC), como o Terraform, para definir e gerir as Step Functions e os Workflows.

Além disso, os Workflows suportam a execução de fluxos de trabalho através das bibliotecas cliente, na Google Cloud consola, através da CLI do Google Cloud ou enviando um pedido para a API REST dos Workflows. Para obter detalhes, consulte Execute um fluxo de trabalho.

Preços

Ambos os produtos têm um nível gratuito. Para mais detalhes, consulte as respetivas páginas de preços: preços do Step Functions e preços do Workflows.

Mapeamento de tipos de estados para passos

Existem oito tipos de estados nas Step Functions. Os estados são elementos numa máquina de estados que podem tomar decisões com base na respetiva entrada, realizar ações e transmitir a saída a outros estados. Antes de migrar das Step Functions para os Workflows, certifique-se de que compreende como traduzir cada tipo de estado num passo dos Workflows.

Choice

Um estado Choice adiciona lógica de ramificação a uma máquina de estados.

Nos fluxos de trabalho, pode usar um bloco switch como um mecanismo de seleção que permite que o valor de uma expressão controle o fluxo de execução de um fluxo de trabalho. Se um valor corresponder, a declaração dessa condição é executada. Para mais informações, consulte as Condições.

Funções escalonadas

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

YAML dos workflows

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

JSON de fluxos de trabalho

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

Fail

Um estado Fail para a execução da máquina de estados e marca-a como uma falha.

Nos fluxos de trabalho, pode gerar erros personalizados através da sintaxe raise e pode detetar e processar erros através de um bloco try/except. Para mais informações, consulte o artigo Gere erros.

Funções escalonadas

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

YAML dos workflows

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

JSON de fluxos de trabalho

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

Map

Um estado Map pode ser usado para executar um conjunto de passos para cada elemento de uma matriz de entrada.

Nos fluxos de trabalho, pode usar forciclos para iterações.

Funções 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 dos workflows

  - 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 fluxos de trabalho

  [
    {
      "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

Um estado Parallel pode ser usado para criar ramificações paralelas de execução na sua máquina de estados. No exemplo seguinte das Step Functions, é realizada uma pesquisa de morada e telefone em paralelo.

Nos fluxos de trabalho, pode usar um passo parallel para definir uma parte do fluxo de trabalho em que dois ou mais passos podem ser executados em simultâneo. Para mais informações, consulte o artigo Passos paralelos.

Funções 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 dos workflows

  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 fluxos de trabalho

  {
    "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

Um estado Pass passa a respetiva entrada para a saída, sem realizar trabalho. Isto é usado comumente para manipular os dados de estado no JSON.

Como o Workflows não transmite dados desta forma, pode deixar o estado como uma operação nula ou usar um passo de atribuição para modificar as variáveis. Para mais informações, consulte o artigo Atribua variáveis.

Funções escalonadas

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

YAML dos workflows

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

JSON de fluxos de trabalho

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

Tenha sucesso

Um estado Succeed interrompe uma execução com êxito.

Nos fluxos de trabalho, pode usar return no fluxo de trabalho principal para parar a execução de um fluxo de trabalho. Também pode concluir um fluxo de trabalho concluindo o passo final (partindo do princípio de que o passo não passa para outro) ou pode usar next: end para parar a execução de um fluxo de trabalho se não precisar de devolver um valor. Para mais informações, consulte o artigo Conclua a execução de um fluxo de trabalho.

Funções escalonadas

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

YAML dos workflows

  return: "Success!"
  next: end

JSON de fluxos de trabalho

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

Task

Um estado Task representa uma única unidade de trabalho realizada por uma máquina de estados. No exemplo das Step Functions seguinte, invoca uma função Lambda. (As atividades são uma funcionalidade do AWS Step Functions que lhe permite ter uma tarefa na sua máquina de estados onde o trabalho é realizado noutro local.)

No exemplo de fluxos de trabalho, é feita uma chamada a um ponto final HTTP para invocar uma função do Cloud Run. Também pode usar um conector que permite o acesso fácil a outros Google Cloud produtos. Além disso, pode pausar um fluxo de trabalho e sondar dados. Em alternativa, pode usar um ponto final de retorno de chamada para sinalizar ao seu fluxo de trabalho que ocorreu um evento especificado e aguardar esse evento sem sondagem.

Funções escalonadas

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

YAML dos workflows

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

JSON de fluxos de trabalho

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

Wait

Um estado Wait atrasa a máquina de estados para continuar durante um período especificado.

Pode usar a sys.sleepfunção da biblioteca padrão dos fluxos de trabalho para suspender a execução durante o número de segundos indicado, até um máximo de 31 536 000 (um ano).

Funções escalonadas

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

YAML dos workflows

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

JSON de fluxos de trabalho

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

Exemplo: orquestrar microsserviços

O exemplo seguinte das Step Functions verifica o preço de uma ação, determina se deve comprar ou vender e comunica o resultado. A máquina de estados no exemplo integra-se com o AWS Lambda através da transmissão de parâmetros, usa uma fila do Amazon SQS para pedir aprovação humana e usa um tópico do Amazon SNS para devolver os resultados da 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
          }
      }
  }

Migre para os fluxos de trabalho

Para migrar o exemplo anterior das Step Functions para os Workflows, pode criar os passos equivalentes dos Workflows integrando funções do Cloud Run, suportando um ponto final de callback que aguarda a chegada de pedidos HTTP a esse ponto final e usando um conector dos Workflows para publicar num tópico do Pub/Sub em vez do tópico do Amazon SNS:

  1. Conclua os passos para criar um fluxo de trabalho, mas não o implemente ainda.

  2. Na definição do fluxo de trabalho, adicione um passo para criar um ponto final de retorno de chamada que aguarde a introdução humana e um passo que use um conector do Workflows para publicar num tópico do Pub/Sub. Por exemplo:

    YAML dos workflows

      ---
      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 fluxos de trabalho

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

    Substitua o seguinte:

    • LOCATION: uma Google Cloud região suportada. Por exemplo, us-central1.
    • PUBSUB_TOPIC_NAME: o nome do seu tópico do Pub/Sub. Por exemplo, my_stock_example.
  3. Implemente e, de seguida, execute o fluxo de trabalho.

  4. Durante a execução do fluxo de trabalho, este é pausado e aguarda que invoque o ponto final de retorno de chamada. Pode usar um comando curl para o fazer. Por exemplo:

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

    Substitua CALLBACK_URL pelo resto do caminho para o seu ponto final de retorno de chamada.

  5. Quando o fluxo de trabalho estiver concluído com êxito, pode receber a mensagem da subscrição do Pub/Sub. Por exemplo:

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

    A mensagem de saída deve ser semelhante à seguinte (buy ou sell):

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

O que se segue?