Migrar da AWS Step Functions para Workflows

Para ajudar você a se preparar para migrar das funções em etapas da Amazon Web Services (AWS) para fluxos de trabalho no Google Cloud, esta página explica as principais semelhanças e diferenças entre os dois produtos. Essas informações têm como objetivo ajudar quem já conhece as funções em etapas a implementar uma arquitetura semelhante usando os fluxos de trabalho.

Assim como as funções em etapas, o Workflows é uma plataforma de orquestração totalmente gerenciada e baseada em estado que executa serviços na ordem que você define, ou seja, em um fluxo de trabalho. Esses fluxos de trabalho podem combinar serviços, incluindo serviços personalizados hospedados no Cloud Run ou nas funções do Cloud Run, Google Cloud serviços como o Cloud Vision AI e o BigQuery, além de qualquer API baseada em HTTP.

Os Fluxos de trabalho Express do Step Functions são um tipo de fluxo de trabalho da AWS Step Functions que não é considerado aqui, porque a duração de um fluxo de trabalho Express é limitada e não há suporte para execução de fluxo de trabalho exatamente uma vez.

Hello World

No Step Functions, uma máquina de estados é um fluxo de trabalho, e uma tarefa é um estado em um fluxo de trabalho que representa uma única unidade de trabalho executada por outro serviço da AWS. As funções em etapas exigem que cada estado defina o próximo estado.

No Workflows, uma série de etapas usando a sintaxe do Workflows descreve as tarefas a serem executadas. O Workflows trata as etapas como se estivessem em uma lista ordenada e as executa uma de cada vez até que todas sejam executadas.

O exemplo "Hello World" a seguir demonstra o uso de estados em funções de etapa e etapas em fluxos de trabalho:

Step Functions

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

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

Visão geral da comparação

Esta seção compara os dois produtos com mais detalhes.

Step FunctionsFluxos de trabalho
SintaxeJSON (YAML nas ferramentas) YAML ou JSON
Fluxo de controleTransição entre estados Controle de fluxo imperativo com etapas
WorkerRecursos (ARN) e tarefa HTTP Solicitações e conectores HTTP
ConfiabilidadePegar/tentar de novo Pegar/tentar de novo
ParalelismoCompatível Compatível
Dados de estadoO estado é transmitido Variáveis do Workflows
AuthenticationIAM IAM
Experiência do usuárioWorkflow Studio, CLI, SDK, IaC Google Cloud console, CLI, SDK, IaC
Preços Preços do Step Functions Preços do Workflows
Sintaxe

O Step Functions usa principalmente JSON para definir funções e não oferece suporte a YAML diretamente. No entanto, no AWS Toolkit para Visual Studio Code e no AWS CloudFormation, é possível usar YAML para uma definição do Step Functions.

É possível descrever as etapas dos fluxos de trabalho usando a sintaxe dos fluxos de trabalho, e elas podem ser gravadas 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 gravação e o suporte nativo a comentários. Para uma explicação detalhada da sintaxe do Workflows, consulte a Referência de sintaxe.

Fluxo de controle

Tanto o Workflows quanto o Step Functions modelam fluxos de trabalho como uma série de tarefas: etapas no Workflows e estados no Step Functions. Ambos permitem que uma tarefa indique qual tarefa será executada em seguida e oferecem suporte a condicionais semelhantes a switch para escolher a próxima unidade de trabalho com base no estado atual. Uma das principais diferenças é que as funções de etapa exigem que cada estado defina o próximo, enquanto os fluxos de trabalho executam as etapas na ordem em que são especificadas (incluindo as próximas etapas alternativas). Para mais informações, consulte Condições e Etapas.

Worker

Ambos os produtos orquestram recursos de computação, como funções, contêineres e outros serviços da Web para realizar tarefas. Nas funções em etapas, o worker é identificado por um campo Resource, que é sintaticamente um URI. Os URIs usados para identificar os recursos do worker estão no formato Amazon Resource Name (ARN). Para invocar diretamente um endpoint HTTP arbitrário, defina uma tarefa HTTP.

Os fluxos de trabalho podem enviar solicitações HTTP para um endpoint HTTP arbitrário e receber uma resposta. Os conectores facilitam a conexão com outras APIs Google Cloud em um fluxo de trabalho e a integração dos fluxos de trabalho com outros produtos Google Cloud , como Pub/Sub, BigQuery ou Cloud Build. Os conectores simplificam os serviços de chamada porque processam a formatação das solicitações, fornecendo métodos e argumentos para que você não precise conhecer os detalhes de uma APIGoogle Cloud . Também é possível configurar as políticas de tempo limite e de pesquisa.

Confiabilidade

Se uma tarefa falhar, o fluxo de trabalho precisa ser capaz de tentar novamente de forma adequada, capturar exceções quando necessário e redirecionar o fluxo de trabalho conforme necessário. Tanto as funções de etapa quanto os fluxos de trabalho alcançam confiabilidade usando mecanismos semelhantes: captura de exceções com reexecuções e envio eventual para outro local no fluxo de trabalho. Para mais informações, consulte Erros de fluxo de trabalho.

Paralelismo

Talvez você queira que seu fluxo de trabalho orquestre várias tarefas em paralelo. As funções de etapa oferecem duas maneiras de fazer isso: você pode pegar um item de dados e transmiti-lo em paralelo para várias tarefas diferentes ou usar uma matriz e transmitir os elementos dela para a mesma tarefa.

No Workflows, é possível definir uma parte do fluxo de trabalho em que duas ou mais etapas podem ser executadas simultaneamente. É possível definir ramos que são executados simultaneamente ou um loop em que as iterações são executadas simultaneamente. Para saber mais, consulte Executar etapas do fluxo de trabalho em paralelo.

Dados de estado

Um dos benefícios de um mecanismo de fluxo de trabalho é que os dados de estado são mantidos para você sem um repositório de dados externo. No Step Functions, os dados de estado são transmitidos em uma estrutura JSON de um estado para outro.

No Workflows, é possível salvar os dados de estado em variáveis globais. Como você tem permissão para até um ano de duração da execução, é possível manter os dados de estado enquanto a instância ainda estiver em execução.

Autenticação

Ambos os produtos dependem de um sistema de gerenciamento de identidade e acesso (IAM) para autenticação e controle de acesso. Por exemplo, é possível usar um papel do IAM para invocar Step Functions.

No Workflows, é possível usar uma conta de serviço para invocar um fluxo de trabalho. Também é possível usar o OAuth 2.0 ou o OIDC para se conectar às APIs Google Cloud. Além disso, é possível usar um cabeçalho de solicitação de autorização para autenticação com uma API de terceiros. Para mais informações, consulte Conceder permissão a um fluxo de trabalho para acessar Google Cloud recursos e Fazer solicitações autenticadas em um fluxo de trabalho.

Experiência do usuário

É possível usar uma ferramenta de linha de comando ou infraestrutura como código (IaC, na sigla em inglês), como o Terraform, para definir e gerenciar funções e fluxos de trabalho.

Além disso, o Workflows oferece suporte à execução de fluxos de trabalho usando as bibliotecas de cliente, o console do Google Cloud, a CLI do Google Cloud ou enviando uma solicitação para a API REST do Workflows. Para mais detalhes, consulte Executar um fluxo de trabalho.

Preços

Os dois produtos têm um nível gratuito. Para mais detalhes, consulte as respectivas páginas de preços: Preços do Step Functions e Preços dos fluxos de trabalho.

Mapeamento de tipos de estado para etapas

Há oito tipos de estado no Step Functions. Os estados são elementos em uma máquina de estados que podem tomar decisões com base na entrada, realizar ações e transmitir a saída para outros estados. Antes de migrar do Step Functions para o Workflows, entenda como converter cada tipo de estado em uma etapa do Workflows.

Choice

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

Nos fluxos de trabalho, é possível usar um bloco switch como um mecanismo de seleção que permite que o valor de uma expressão controle o fluxo da execução de um fluxo de trabalho. Se um valor corresponder, a instrução dessa condição será executada. Para mais informações, consulte Condições.

Step Functions

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

YAML de fluxos de trabalho

  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 interrompe a execução da máquina de estados e a marca como falha.

Nos fluxos de trabalho, é possível gerar erros personalizados usando a sintaxe raise e capturar e processar erros usando um bloco try/except. Para mais informações, consulte Como gerar erros.

Step Functions

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

YAML de fluxos de trabalho

  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 etapas para cada elemento de uma matriz de entrada.

Nos fluxos de trabalho, é possível usar loops for para iterações.

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

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 máquina de estados. No exemplo de Step Functions abaixo, uma pesquisa de endereço e telefone é realizada em paralelo.

Nos fluxos de trabalho, é possível usar uma etapa parallel para definir uma parte do fluxo de trabalho em que duas ou mais etapas podem ser executadas simultaneamente. Para mais informações, consulte Etapas paralelas.

Step Functions

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

  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 transmite a entrada para a saída sem realizar trabalho. Isso é comumente usado para manipular os dados de estado no JSON.

Como os fluxos de trabalho não transmitem dados dessa maneira, você pode deixar o estado como uma operação nula ou usar uma etapa de atribuição para modificar as variáveis. Para mais informações, consulte Atribuir variáveis.

Step Functions

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

YAML de fluxos de trabalho

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

Sucesso

Um estado Succeed interrompe uma execução.

Nos fluxos de trabalho, é possível usar return no fluxo principal para interromper a execução de um fluxo de trabalho. Você também pode concluir um fluxo de trabalho concluindo a etapa final (assumindo que a etapa não salte para outra) ou usar next: end para interromper a execução de um fluxo de trabalho se não precisar retornar um valor. Para mais informações, consulte Concluir a execução de um fluxo de trabalho.

Step Functions

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

YAML de fluxos de trabalho

  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 de Step Functions a seguir, ele invoca uma função Lambda. As atividades são um recurso da AWS Step Functions que permite ter uma tarefa no seu estado em que o trabalho é realizado em outro lugar.

No exemplo de fluxos de trabalho, uma chamada é feita para um endpoint HTTP para invocar uma função do Cloud Run. Também é possível usar um conector que permite acesso fácil a outros produtos Google Cloud . Além disso, é possível pausar um fluxo de trabalho e consultar dados. Também é possível usar um endpoint de callback para sinalizar ao fluxo de trabalho que um evento especificado ocorreu e aguardar esse evento sem a necessidade de pesquisa.

Step Functions

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

YAML de fluxos de trabalho

  - 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 continuidade da máquina de estados por um período especificado.

É possível usar a função da biblioteca padrão sys.sleep do Workflows para suspender a execução pelo número determinado de segundos até um máximo de 31536000 (um ano).

Step Functions

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

YAML de fluxos de trabalho

  - 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 de Step Functions a seguir verifica o preço de uma ação, determina se ela deve ser comprada ou vendida e informa o resultado. A máquina de estados no exemplo se integra à AWS Lambda transmitindo parâmetros, usa uma fila do Amazon SQS para solicitar aprovação humana e usa um tópico do Amazon SNS para retornar 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
          }
      }
  }

Migrar para os fluxos de trabalho

Para migrar o exemplo anterior do Step Functions para o Workflows, crie as etapas equivalentes do Workflows integrando funções do Cloud Run, com suporte a um endpoint de callback que aguarda a chegada de solicitações HTTP a esse endpoint e use um conector do Workflows para publicar em um tópico do Pub/Sub em vez do tópico do Amazon SNS:

  1. Siga as etapas para criar um fluxo de trabalho, mas não o implante ainda.

  2. Na definição do fluxo de trabalho, adicione uma etapa para criar um endpoint de callback que aguarde a entrada humana e uma etapa que use um conector do Workflows para publicar em um tópico do Pub/Sub. Exemplo:

    YAML 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
      ...

    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:

    • LOCATION: uma regiãoGoogle Cloud com suporte. Por exemplo, us-central1.
    • PUBSUB_TOPIC_NAME: o nome do tópico do Pub/Sub. Por exemplo, my_stock_example.
  3. Implante e execute o fluxo de trabalho.

  4. Durante a execução do fluxo de trabalho, ele é pausado e aguarda que você invoque o endpoint de callback. Você pode usar um comando curl para fazer isso. Exemplo:

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

    Substitua CALLBACK_URL pelo restante do caminho para o endpoint de callback.

  5. Depois que o fluxo de trabalho for concluído, você poderá receber a mensagem da assinatura do Pub/Sub. Exemplo:

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

    A mensagem de saída será semelhante a esta (buy ou sell):

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

A seguir