Migrar do AWS Step Functions para o Workflows

Para ajudar você a se preparar para migrar das funções de etapa da Amazon Web Services (AWS) para Workflows no Google Cloud, esta página explica as principais semelhanças e diferenças entre os dois produtos. Essas informações servem para ajudar as pessoas que já estão familiarizadas com as funções de etapa a implementar uma arquitetura semelhante usando o Workflows.

Assim como o Step Functions, o Workflows é uma plataforma de orquestração totalmente gerenciada baseada em estado que executa serviços em uma ordem definida por você: um fluxo de trabalho. Esses fluxos de trabalho podem combinar serviços, incluindo serviços personalizados hospedados no Cloud Run ou no Cloud Functions, serviços do Google Cloud, como Cloud Vision AI e BigQuery, e qualquer API baseada em HTTP.

Observe que o Express Workflows de etapas de etapa da AWS é um tipo de fluxo de trabalho de funções de etapa da AWS que não é considerado aqui porque a duração de um fluxo de trabalho do Express é limitada e não há suporte para a execução de um fluxo de trabalho exatamente uma vez.

Hello World

Nas funções de etapa, uma máquina de estado é um fluxo de trabalho. 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 de etapa exigem que todos os estados definam o próximo.

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

O exemplo "Hello world" a seguir demonstra o uso de estados nas funções de etapa e de etapas nos Workflows:

Funções de etapa

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

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

Visão geral da comparação

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

Funções de etapaFluxos de trabalho
SintaxeJSON (YAML nas ferramentas) YAML ou JSON
Fluxo de controleTransição entre estados Controle imperativo de fluxo com etapas
WorkerRecursos (ARN) Solicitações HTTP e conectores
ConfiabilidadeCapturar/tentar de novo Capturar/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 Console do Google Cloud, CLI, SDK, IaC
Preços Preços das funções de etapa Preços dos fluxos de trabalho
Sintaxe

As funções de etapa usam principalmente JSON para definir funções e não são compatíveis com YAML diretamente. No entanto, no AWS Toolkit para Visual Studio Code e no AWS CloudFormation, é possível usar o YAML para uma definição das funções de etapa.

É possível descrever as etapas do Workflows usando a sintaxe dele, e elas podem ser escritas em YAML ou JSON. A maioria dos fluxos de trabalho está em YAML. Nos exemplos desta página, demonstramos as vantagens do YAML, incluindo a facilidade de leitura e gravação e o suporte nativo a comentários. Para uma explicação detalhada sobre a 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: steps em fluxos de trabalho e states em funções de etapa. Ambos permitem que uma tarefa indique qual tarefa será executada em seguida e oferecem suporte a condicionais do tipo 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 todos os estados definam o próximo, enquanto o Workflows executa as etapas na ordem em que são especificadas (incluindo as próximas etapas alternativas). Para mais informações, consulte Condições e Etapas.

intelectual

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

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

Confiabilidade

Se uma tarefa falhar, seu fluxo de trabalho precisará ser capaz de tentar novamente, detectar exceções quando necessário e redirecionar o fluxo de trabalho conforme necessário. As funções de etapa e Workflows alcançam confiabilidade usando mecanismos semelhantes: captura de exceções com novas tentativas e envio posterior para outro lugar no fluxo de trabalho. Para mais informações, consulte Erros de fluxo de trabalho.

Paralelismo

O fluxo de trabalho pode orquestrar várias tarefas em paralelo. O Step Functions oferece duas maneiras de fazer isso: é possível receber um item de dados e passá-lo em paralelo a várias tarefas diferentes ou usar uma matriz e transmitir os elementos dele para a mesma tarefa.

No Workflows, é possível definir uma parte do seu fluxo de trabalho em que duas ou mais etapas podem ser executadas simultaneamente. Você pode definir ramificações que são executadas simultaneamente ou um loop em que as iterações são executadas simultaneamente. Para mais detalhes, consulte Executar etapas do fluxo de trabalho em paralelo.

Dados de estado

Um benefício de um mecanismo de fluxo de trabalho é que os dados de estado são mantidos para você sem um repositório de dados externo. Nas funções de etapa, os dados de estado são transmitidos em uma estrutura JSON de um estado para outro.

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

Autenticação

Os dois produtos dependem de um sistema do Identity and Access Management (IAM) subjacente para autenticação e controle de acesso. Por exemplo, é possível usar um papel do IAM para invocar funções de etapa.

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

Experiência do usuário

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

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

Preços

Ambos os produtos têm um nível gratuito. Para mais detalhes, consulte as respectivas páginas de preços: Preços das funções de etapas e Preços dos fluxos de trabalho.

Mapeamento de tipos de estado para etapas

Há oito tipos de estado nas funções de etapa. Os estados são elementos em uma máquina de estado que pode tomar decisões com base nas entradas, executar ações e transmitir a saída para outros estados. Antes de migrar do Step Functions para Workflows, verifique como converter cada tipo de estado em uma etapa do Workflows.

Choice

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

No Workflows, é possível usar um bloco switch como 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 instrução dessa condição será executada. Para mais informações, consulte Condições.

Funções de etapa

  "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 do Workflows

  {
    "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 estado e a marca como uma falha.

No Workflows, é possível gerar erros personalizados usando a sintaxe raise, e você pode capturar e processar erros usando um bloco try/except. Para mais informações, consulte Informar erros.

Funções de etapa

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

YAML de fluxos de trabalho

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

JSON do Workflows

  {
    "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 repetições for para iterações.

Funções de etapa

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

Parallel

Um estado Parallel pode ser usado para criar ramificações paralelas de execução na sua máquina de estado. No exemplo da função de etapa a seguir, uma pesquisa de endereço e telefone é realizada em paralelo.

No Workflows, você pode 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.

Funções de etapa

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

  {
    "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 o trabalho. Isso é frequentemente usado para manipular os dados de estado no JSON.

Como o Workflows não transmite dados dessa maneira, é possível deixar o estado como um ambiente autônomo ou usar uma etapa de atribuição para modificar as variáveis. Para mais informações, consulte Atribuir variáveis.

Funções de etapa

  "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 do Workflows

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

Sucesso

Um estado Succeed interrompe uma execução.

No Workflows, é possível usar return no fluxo de trabalho principal para interromper a execução de um fluxo de trabalho. Também é possível finalizar um fluxo de trabalho concluindo a etapa final (supondo que a etapa não pule 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.

Funções de etapa

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

YAML de fluxos de trabalho

  return: "Success!"
  next: end

JSON do Workflows

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

Task

Um estado Task representa uma única unidade de trabalho realizado por uma máquina de estado. No exemplo da função de etapa a seguir, ele invoca uma função Lambda. Atividades são um recurso de funções de etapa da AWS que permite que você tenha uma tarefa na máquina de estado em que o trabalho é executado em outro lugar.

No exemplo do Workflows, uma chamada é feita para um endpoint HTTP para invocar uma função do Cloud. Também é possível usar um conector que facilite o acesso a outros produtos do Google Cloud. Além disso, é possível pausar um fluxo de trabalho e pesquisar 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 pesquisar.

Funções de etapa

  "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 do Workflows

  [
    {
      "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 estado por um período especificado.

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

Funções de etapa

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

YAML de fluxos de trabalho

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

JSON do Workflows

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

Exemplo: orquestrar microsserviços

O exemplo de funções de etapa a seguir verifica o preço de uma ação, determina se vai comprar ou vender e informa o resultado. A máquina de estado na amostra integra-se ao AWS Lambda ao transmitir 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 o Workflows

Para migrar o exemplo anterior das funções de etapa para o Workflows, você pode criar as etapas equivalentes do Workflows integrando o Cloud Functions, oferecendo suporte a um endpoint de callback que aguarda a chegada de solicitações HTTP nesse endpoint e usando um conector do Workflows para publicar em um tópico do Pub/Sub em vez do tópico do Amazon SNS:

  1. Conclua 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 do 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"
              }
            }
          ]
        }
      }

    Substitua:

    • LOCATION: uma região do Google Cloud compatível. 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 espera até 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 com êxito, será possível 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 (uma buy ou um sell):

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

A seguir