Eseguire la migrazione da AWS Step Functions a Workflows

Per aiutarti a prepararti alla migrazione da Step Functions di Amazon Web Services (AWS) a Workflows su Google Cloud, questa pagina illustra le principali somiglianze e differenze tra i due prodotti. Queste informazioni hanno lo scopo di aiutare coloro che hanno già familiarità con Step Functions a implementare un'architettura simile utilizzando Workflows.

Come Step Functions, Workflows è una piattaforma di orchestrazione basata sugli stati completamente gestita che esegue i servizi in un ordine definito da te: un flusso di lavoro. Questi flussi di lavoro possono combinare servizi, inclusi servizi personalizzati ospitati su Cloud Run o funzioni Cloud Run, servizi Google Cloud come Cloud Vision AI e BigQuery e qualsiasi API basata su HTTP.

Tieni presente che i workflow express di Step Functions sono un tipo di flusso di lavoro AWS Step Functions che non viene preso in considerazione qui perché la durata di un flusso di lavoro express è limitata e l'esecuzione di un flusso di lavoro esattamente una volta non è supportata.

Hello World

In Step Functions, una macchina a stati è un flusso di lavoro e un'attività è uno stato in un flusso di lavoro che rappresenta una singola unità di lavoro eseguita da un altro servizio AWS. Step Functions richiede che ogni stato definisca lo stato successivo.

In Workflows, una serie di passaggi che utilizzano la sintassi di Workflows descrive le attività da eseguire. Workflows trattano i passaggi come se fossero in un elenco ordinato e li eseguono uno alla volta fino a quando non sono stati eseguiti tutti.

Il seguente esempio "Hello world" mostra l'utilizzo degli stati nelle funzioni di passaggio e dei passaggi nei Workflows:

Funzioni a gradino

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

File YAML dei workflow

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

JSON dei flussi di lavoro

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

Panoramica del confronto

Questa sezione mette a confronto i due prodotti in modo più dettagliato.

Funzioni a gradinoWorkflows
SintassiJSON (YAML negli strumenti) YAML o JSON
Flusso di controlloTransizione tra gli stati Controllo del flusso imperativo con i passaggi
LavoratoreRisorse (ARN) e attività HTTP Richieste e connettori HTTP
AffidabilitàCattura/riprova Cattura/riprova
ParallelismiSupportato Supportato
Dati stataliLo stato viene trasmesso Variabili di Workflows
AutenticazioneIAM IAM
Esperienza utenteWorkflow Studio, CLI, SDK, IaC Console, CLI, SDK e IaC di Google Cloud
Prezzi Prezzi di Step Functions Prezzi di Workflows
Sintassi

Step Functions utilizza principalmente JSON per definire le funzioni e non supporta direttamente YAML. Tuttavia, in AWS Toolkit per Visual Studio Code e in AWS CloudFormation puoi utilizzare YAML per una definizione di Step Functions.

Puoi descrivere i passaggi di Workflows utilizzando la sintassi di Workflows e possono essere scritti in YAML o JSON. La maggior parte dei flussi di lavoro sono in YAML. Gli esempi in questa pagina mostrano i vantaggi di YAML, tra cui la facilità di lettura e scrittura e il supporto nativo dei commenti. Per una spiegazione dettagliata della sintassi di Workflows, consulta il riferimento alla sintassi.

Flusso di controllo

Sia Workflows sia Step Functions modellano i flussi di lavoro come una serie di attività: passaggi in Workflows e stati in Step Functions. Entrambi consentono a un'attività di indicare quale eseguire successivamente e supportano i condizionali simili a switch per scegliere l'unità di lavoro successiva in base allo stato corrente. Una differenza fondamentale è che Step Functions richiede che ogni stato definisca quello successivo, mentre Workflows esegue i passaggi nell'ordine in cui sono specificati (inclusi i passaggi successivi alternativi). Per ulteriori informazioni, consulta Condizioni e Passaggi.

Worker

Entrambi i prodotti orchestrano risorse di calcolo come funzioni, container e altri servizi web per svolgere attività. In Step Functions, il worker è identificato da un campo Resource che è sintatticamente un URI. Gli URI utilizzati per identificare le risorse dei worker sono in formato Amazon Resource Name (ARN). Per invocare direttamente un endpoint HTTP arbitrario, puoi definire un'attività HTTP.

Workflows possono inviare richieste HTTP a un endpoint HTTP arbitrario e ricevere una risposta. I connettori semplificano la connessione ad altre API Google Cloud all'interno di un flusso di lavoro e l'integrazione dei flussi di lavoro con altri prodotti Google Cloud come Pub/Sub, BigQuery o Cloud Build. I connettori simplificano le chiamate ai servizi perché gestiscono la formattazione delle richieste per te, fornendo metodi e argomenti in modo da non dover conoscere i dettagli di un' API Google Cloud. Puoi anche configurare i criteri di timeout e polling.

Affidabilità

Se un'attività non va a buon fine, il flusso di lavoro deve essere in grado di riprovare in modo appropriato, intercettare le eccezioni quando necessario e reindirizzare il flusso di lavoro in base alle necessità. Sia le funzioni di riga sia Workflows raggiungono l'affidabilità utilizzando meccanismi simili: rilevamento delle eccezioni con i tentativi di nuovo invio ed eventuale invio altrove nel flusso di lavoro. Per ulteriori informazioni, vedi Errori di flusso di lavoro.

Parallelismo

Potresti voler orchestrare più attività in parallelo nel tuo flusso di lavoro. Le funzioni di riga forniscono due modi per farlo: puoi prendere un elemento dati e passarlo in parallelo a più attività diverse oppure puoi utilizzare un array e passare i relativi elementi alla stessa attività.

In Workflows, puoi definire una parte del flusso di lavoro in cui due o più passaggi possono essere eseguiti contemporaneamente. Puoi definire rami che vengono eseguiti contemporaneamente o un ciclo in cui le iterazioni vengono eseguite contemporaneamente. Per maggiori dettagli, vedi Eseguire i passaggi del flusso di lavoro in parallelo.

Dati dello stato

Uno dei vantaggi di un motore di flusso di lavoro è che i dati di stato vengono gestiti per te senza un archivio dati esterno. In Step Functions, i dati dello stato vengono trasmessi in una struttura JSON da uno stato all'altro.

In Workflows, puoi salvare i dati dello stato nelle variabili globali. Poiché è consentita una durata dell'esecuzione massima di un anno, puoi conservare i dati dello stato finché l'istanza è ancora in esecuzione.

Autenticazione

Entrambi i prodotti si basano su un sistema Identity and Access Management (IAM) sottostante per l'autenticazione e controllo dell'accesso dell'accesso. Ad esempio, puoi utilizzare un ruolo IAM per invocare Step Functions.

In Workflows, puoi utilizzare un account di servizio per invocare un flusso di lavoro, OAuth 2.0 o OIDC per connetterti alle API Google Cloud e un'intestazione di richiesta di autorizzazione per autenticarti con un'API di terze parti. Per ulteriori informazioni, consulta Concedere un'autorizzazione di flusso di lavoro per accedere alle risorse Google Cloud e Eseguire richieste autenticate da un flusso di lavoro.

Esperienza utente

Puoi utilizzare uno strumento a riga di comando o Infrastructure as Code (IaC) come Terraform per definire e gestire sia le funzioni di passaggio sia Workflows.

Inoltre, Workflows supporta l'esecuzione dei flussi di lavoro utilizzando le librerie client, nella console Google Cloud, con Google Cloud CLI o inviando una richiesta all'API REST di Workflows. Per maggiori dettagli, consulta Eseguire un flusso di lavoro.

Prezzi

Entrambi i prodotti hanno un livello gratuito. Per ulteriori dettagli, consulta le rispettive pagine dei prezzi: Prezzi di Step Functions e Prezzi di Workflows.

Mappatura dei tipi di stato ai passaggi

In Step Functions esistono otto tipi di stati. Gli stati sono elementi di una macchina a stati che possono prendere decisioni in base ai propri input, eseguire azioni e passare l'output ad altri stati. Prima di eseguire la migrazione da Step Functions a Workflows, assicurati di capire come tradurre ogni tipo di stato in un passaggio di Workflows.

Choice

Uno stato Choice aggiunge la logica di ramificazione a una macchina a stati.

Nei flussi di lavoro, puoi utilizzare un blocco switch come meccanismo di selezione che consente al valore di un'espressione di controllare il flusso di esecuzione di un flusso di lavoro. Se un valore corrisponde, viene eseguito l'istruzione della condizione. Per ulteriori informazioni, consulta la sezione Condizioni.

Funzioni a gradino

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

File YAML dei workflow

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

JSON dei flussi di lavoro

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

Fail

Uno stato Fail interrompe l'esecuzione della macchina a stati e lo contrassegna come un errore.

In Workflows, puoi generare errori personalizzati utilizzando la sintassi raise e puoi intercettare e gestire gli errori utilizzando un blocco try/except. Per maggiori informazioni, consulta Generare errori.

Funzioni a gradino

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

File YAML dei workflow

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

JSON dei flussi di lavoro

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

Map

Uno stato Map può essere utilizzato per eseguire una serie di passaggi per ogni elemento di un array di input.

In Workflows, puoi utilizzare un for loop per iterations.

Funzioni a gradino

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

File YAML dei workflow

  - 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 dei flussi di lavoro

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

Uno stato Parallel può essere utilizzato per creare branche di esecuzione parallele nella macchina a stati. Nel seguente esempio di Step Functions, viene eseguita una ricerca di indirizzi e numeri di telefono in parallelo.

In Workflows, puoi utilizzare un passaggio parallel per definire una parte del flusso di lavoro in cui due o più passaggi possono essere eseguiti contemporaneamente. Per ulteriori informazioni, consulta Passaggi paralleli.

Funzioni a gradino

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

File YAML dei workflow

  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 dei flussi di lavoro

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

Uno stato Pass passa il proprio input all'output, senza eseguire alcuna operazione. Questo metodo viene spesso utilizzato per manipolare i dati dello stato in JSON.

Poiché i flussi di lavoro non trasmettono i dati in questo modo, puoi lasciare lo stato come no-op oppure utilizzare un passaggio di assegnazione per modificare le variabili. Per ulteriori informazioni, consulta Assegnare variabili.

Funzioni a gradino

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

File YAML dei workflow

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

JSON dei flussi di lavoro

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

Riuscire

Uno stato Succeed interrompe un'esecuzione correttamente.

In Flussi di lavoro, puoi utilizzare return nel flusso di lavoro principale per interrompere l'esecuzione di un flusso di lavoro. Puoi anche completare un flusso di lavoro completando il passaggio finale (supponendo che il passaggio non passi a un altro) oppure puoi utilizzare next: end per interrompere l'esecuzione di un flusso di lavoro se non devi restituire un valore. Per saperne di più, consulta Completare l'esecuzione di un flusso di lavoro.

Funzioni a gradino

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

File YAML dei workflow

  return: "Success!"
  next: end

JSON dei flussi di lavoro

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

Task

Uno stato Task rappresenta una singola unità di lavoro eseguita da una macchina a stati. Nel seguente esempio di Step Functions, viene richiamata una funzione Lambda. Le attività sono una funzionalità di AWS Step Functions che ti consente di avere un'attività nel tuo macchinario a stato in cui il lavoro viene eseguito altrove.

Nell'esempio di Workflows, viene eseguita una chiamata a un endpoint HTTP per richiamare una funzione Cloud Run. Puoi anche utilizzare un connettore che consente di accedere facilmente ad altri prodotti Google Cloud. Inoltre, puoi mettere in pausa un flusso di lavoro ed eseguire il polling dei dati. In alternativa, puoi utilizzare un endpoint di callback per segnalare al flusso di lavoro che si è verificato un evento specifico e attendere questo evento senza eseguire polling.

Funzioni a gradino

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

File YAML dei workflow

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

JSON dei flussi di lavoro

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

Wait

Uno stato Wait impedisce alla macchina a stati di continuare per un periodo di tempo specificato.

Puoi utilizzare la sys.sleep funzione della libreria standard di Workflows per sospensione dell'esecuzione per il numero di secondi specificato fino a un massimo di 31536000 (un anno).

Funzioni a gradino

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

File YAML dei workflow

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

JSON dei flussi di lavoro

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

Esempio: orchestrare i microservizi

Il seguente esempio di Step Functions controlla il prezzo di un'azione, determina se acquistare o vendere e riporta il risultato. Il macchinario a stati nell'esempio si integra con AWS Lambda passando i parametri, utilizza una coda Amazon SQS per richiedere l'approvazione da parte di un utente e utilizza un argomento Amazon SNS per restituire i risultati della query.

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

Eseguire la migrazione a Workflows

Per eseguire la migrazione dell'esempio di Step Functions precedente a Workflows, puoi creare i passaggi di Workflows equivalenti integrando funzioni Cloud Run, supportando un endpoint di callback che attende l'arrivo di richieste HTTP in quell'endpoint e utilizzando un connettore Workflows per pubblicare in un argomento Pub/Sub al posto dell'argomento Amazon SNS:

  1. Completa i passaggi per creare un flusso di lavoro, ma non eseguirlo ancora.

  2. Nella definizione del flusso di lavoro, aggiungi un passaggio per creare un endpoint di callback che attende l'input di una persona e un passaggio che utilizza un connettore Workflows per pubblicare in un argomento Pub/Sub. Ad esempio:

    File YAML dei workflow

      ---
      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 dei flussi di lavoro

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

    Sostituisci quanto segue:

    • LOCATION: una regione Google Cloud supportata. Ad esempio: us-central1.
    • PUBSUB_TOPIC_NAME: il nome dell'argomento Pub/Sub. Ad esempio, my_stock_example.
  3. Esegui il deployment e poi esegui il flusso di lavoro.

  4. Durante l'esecuzione del flusso di lavoro, viene messo in pausa e attende che tu richiami l'endpoint di callback. Per farlo, puoi utilizzare un comando curl. Ad esempio:

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

    Sostituisci CALLBACK_URL con il resto del percorso all'endpoint di callback.

  5. Una volta completato il flusso di lavoro, puoi ricevere il messaggio dall'abbonamento Pub/Sub. Ad esempio:

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

    Il messaggio di output dovrebbe essere simile al seguente (buy o sell):

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

Passaggi successivi