Esegui la migrazione da AWS Step Functions a Workflows

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

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

Tieni presente che Step Functions Express Workflows è un tipo di flusso di lavoro di AWS Step Functions che non viene considerato qui, poiché la durata di un flusso di lavoro Express è limitata e l'esecuzione di un flusso di lavoro "exactly-once" non è supportata.

Hello World

In Step Functions, una macchina a stati è un flusso di lavoro e un'attività è uno stato di 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 utilizza la sintassi di Workflows descrive le attività da eseguire. Workflows tratta i passaggi come se fossero in un elenco ordinato e li esegue uno alla volta fino all'esecuzione di tutti i passaggi.

Il seguente esempio "Hello world" mostra l'utilizzo degli stati in Step Functions e nei steps in Workflows:

Funzioni dei passaggi

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

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

JSON Workflows

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

Panoramica del confronto

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

Funzioni dei passaggiWorkflows
SintassiJSON (YAML negli strumenti) YAML o JSON
Controllo del flussoTransizione tra gli stati Controllo del flusso imperativo con passi
WorkerRisorse (ARN) Richieste HTTP e connettori
AffidabilitàCattura/riprova Cattura/riprova
ParallelismoSupportato Supportato
Dati relativi allo statoLo stato viene trasmesso Variabili Workflows
AutenticazioneIAM IAM
Esperienza utenteWorkflow Studio, interfaccia a riga di comando, SDK, IaC Console Google Cloud, interfaccia a riga di comando, SDK, IaC
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 for 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 Workflows, e puoi scriverli in formato YAML o JSON. La maggior parte dei flussi di lavoro è 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 per la sintassi.

Flusso di controllo

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

Worker

Entrambi i prodotti orchestrano le risorse di computing, come funzioni, container e altri servizi web, per portare a termine ogni attività. In Step Functions, il worker è identificato da un campo Resource che è sintatticamente un URI. Gli URI utilizzati per identificare le risorse worker sono in formato Amazon Resource Name (ARN) e gli utenti non possono richiamare direttamente un endpoint HTTP arbitrario.

Workflows possono inviare richieste HTTP a un endpoint HTTP arbitrario e ottenere 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 semplificano i servizi di chiamata perché gestiscono la formattazione delle richieste per conto tuo, fornendo metodi e argomenti in modo che non sia necessario conoscere i dettagli di un'API Google Cloud. Puoi anche configurare i criteri di timeout e di polling.

Affidabilità

Se un'attività non va a buon fine, il flusso di lavoro deve essere in grado di riprovare in modo appropriato, rilevare eccezioni quando necessario e reindirizzare il flusso di lavoro in base alle esigenze. Sia la funzione Step e Workflows ottengono l'affidabilità utilizzando meccanismi simili: rilevamento delle eccezioni con i nuovi tentativi ed invio finale in altre parti del flusso di lavoro. Per ulteriori informazioni, consulta Errori del flusso di lavoro.

Parallelismo

Potrebbe essere opportuno che il tuo flusso di lavoro orchestra più attività in parallelo. La funzione Step Functions offre due modi per raggiungere questo obiettivo: puoi prendere un elemento di dati e passarlo in parallelo a più attività diverse oppure utilizzare un array e trasferire 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 in esecuzione contemporaneamente o un loop in cui le iterazioni vengono eseguite contemporaneamente. Per maggiori dettagli, consulta Eseguire in parallelo i passaggi del flusso di lavoro.

Dati stato

Uno dei vantaggi di un motore del flusso di lavoro è che i dati di stato vengono conservati automaticamente senza un datastore esterno. In Step Functions, i dati di stato vengono passati in una struttura JSON da uno stato all'altro.

In Workflows puoi salvare i dati dello stato in variabili globali. Poiché è consentita una durata di esecuzione fino a un anno, puoi conservare i dati di 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. Ad esempio, puoi usare un ruolo IAM per richiamare le funzioni passo.

In Workflows puoi utilizzare un account di servizio per richiamare un flusso di lavoro, OAuth 2.0 o OIDC per la connessione alle API Google Cloud e l'intestazione di una richiesta di autorizzazione per l'autenticazione con un'API di terze parti. Per maggiori informazioni, vedi Concedere l'autorizzazione di un flusso di lavoro per l'accesso alle risorse Google Cloud ed Effettuare 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 Step che i Workflows.

Inoltre, Workflows supporta l'esecuzione di flussi di lavoro utilizzando le librerie client, nella console Google Cloud, utilizzando Google Cloud CLI o inviando una richiesta all'API REST Workflows. Per maggiori dettagli, consulta Esecuzione di 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 ci sono otto tipi di stato. Gli stati sono elementi di una macchina a stato che possono prendere decisioni in base ai loro input, eseguire azioni e passare l'output ad altri stati. Prima di eseguire la migrazione da Step Functions a Workflows, assicurati di comprendere come tradurre ogni tipo di stato in un passaggio di Workflows.

Choice

Uno stato Choice aggiunge una logica di diramazione a una macchina a stati.

In Workflows, 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 eseguita l'istruzione di quella condizione. Per ulteriori informazioni, consulta la sezione Condizioni.

Funzioni dei passaggi

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

YAML Workflows

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

JSON Workflows

  {
    "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 stato e la contrassegna come errore.

In Workflows, puoi segnalare errori personalizzati utilizzando la sintassi raise e rilevare e gestire gli errori utilizzando un blocco try/except. Per ulteriori informazioni, consulta la sezione Segnalare errori.

Funzioni dei passaggi

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

YAML Workflows

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

JSON Workflows

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

Map

È possibile utilizzare uno stato Map per eseguire una serie di passaggi per ogni elemento di un array di input.

In Workflows, puoi utilizzare un loop for per le iterazioni.

Funzioni dei passaggi

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

  - assignStep:
      assign:
        - map:
            1: 10
            2: 20
            3: 30
        - sum: 0
  - loopStep:
      for:
          value: key
          in: ${keys(map)}
          steps:
            - sumStep:
                assign:
                  - sum: ${sum + map[key]}
  - returnStep:
      return: ${sum}

JSON 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

È possibile usare uno stato Parallel per creare rami di esecuzione paralleli nella tua macchina a stato. Nel seguente esempio di Step Functions, una ricerca di indirizzi e telefono viene eseguita 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 saperne di più, consulta la sezione Passaggi paralleli.

Funzioni dei passaggi

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

  main:
     params: [args]
     steps:
     - init:
         assign:
         - workflow_id: "lookupAddress"
         - customer_to_lookup:
             - address: ${args.customerId}
             - phone: ${args.customerId}
         - addressed: ["", ""] # to write to this variable, you must share it
     - parallel_address:
         parallel:
             shared: [addressed]
             for:
                 in: ${customer_to_lookup}
                 index: i # optional, use if index is required
                 value: arg
                 steps:
                 - address:
                     call: googleapis.workflowexecutions.v1.projects.locations.workflows.executions.run
                     args:
                         workflow_id: ${workflow_id}
                         argument: ${arg}
                     result: r
                 - set_result:
                     assign:
                     - addressed[i]: ${r}
     - return:
             return: ${addressed}

JSON 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

Uno stato Pass trasmette il proprio input all'output, senza eseguire operazioni. Viene generalmente utilizzato per manipolare i dati di stato nel formato JSON.

Poiché Workflows non trasmette i dati in questo modo, puoi lasciare lo stato inutilizzabile o utilizzare un passaggio di assegnazione per modificare le variabili. Per ulteriori informazioni, consulta Assegnare variabili.

Funzioni dei passaggi

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

YAML Workflows

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

JSON Workflows

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

Riuscito

Lo stato Succeed interrompe un'esecuzione.

In Workflows, 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 maggiori informazioni, consulta Completare l'esecuzione di un flusso di lavoro.

Funzioni dei passaggi

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

YAML Workflows

  return: "Success!"
  next: end

JSON Workflows

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

Task

Uno stato Task rappresenta una singola unità di lavoro eseguita da una macchina a stati. Nell'esempio di Step Functions riportato di seguito, richiama una funzione Lambda. (Le attività sono una funzionalità delle funzioni passo di AWS che consente di avere un'attività nella macchina a stati in cui il lavoro viene eseguito altrove.)

Nell'esempio Workflows, viene effettuata una chiamata a un endpoint HTTP per richiamare una Cloud Function. Puoi anche utilizzare un connettore che consente un facile accesso ad altri prodotti Google Cloud. Inoltre, puoi mettere in pausa un flusso di lavoro e eseguire il polling dei dati. In alternativa, puoi utilizzare un endpoint di callback per segnalare al tuo flusso di lavoro che si è verificato un evento specificato e attendere su quell'evento senza polling.

Funzioni dei passaggi

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

YAML Workflows

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

JSON Workflows

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

Wait

Uno stato Wait ritarda l'esecuzione della macchina a stato per un periodo di tempo specificato.

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

Funzioni dei passaggi

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

YAML Workflows

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

JSON Workflows

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

Esempio: orchestrare i microservizi

L'esempio di Step Functions riportato di seguito controlla il prezzo di un'azione, determina se acquistare o vendere e segnala il risultato. La macchina a stati nell'esempio si integra con AWS Lambda passando parametri, utilizza una coda Amazon SQS per richiedere l'approvazione da parte di persone fisiche 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
          }
      }
  }

Esegui la migrazione a Workflows

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

  1. Completa la procedura per creare un flusso di lavoro, ma non eseguirne ancora il deployment.

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

    YAML Workflows

      ---
      main:
        steps:
          - init:
              assign:
                - projectId: '${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}'
                - region: LOCATION
                - topic: PUBSUB_TOPIC_NAME
          - Check Stock Price:
              call: http.get
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/CheckStockPrice"}
                auth:
                  type: OIDC
              result: stockPriceResponse
          - Generate Buy/Sell Recommendation:
              call: http.get
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/BuySellRecommend"}
                auth:
                  type: OIDC
                query:
                  price: ${stockPriceResponse.body.stock_price}
              result: recommendResponse
          - Create Approval Callback:
              call: events.create_callback_endpoint
              args:
                  http_callback_method: "GET"
              result: callback_details
          - Print Approval Callback Details:
              call: sys.log
              args:
                  severity: "INFO"
                  text: ${"Listening for callbacks on " + callback_details.url}
          - Await Approval Callback:
              call: events.await_callback
              args:
                  callback: ${callback_details}
                  timeout: 3600
              result: approvalResponse
          - Approval?:
              try:
                switch:
                  - condition: ${approvalResponse.http_request.query.response[0] == "yes"}
                    next: Buy or Sell?
              except:
                as: e
                steps:
                  - unknown_response:
                      raise: ${"Unknown response:" + e.message}
                      next: end
          - Buy or Sell?:
              switch:
                - condition: ${recommendResponse.body == "buy"}
                  next: Buy Stock
                - condition: ${recommendResponse.body == "sell"}
                  next: Sell Stock
                - condition: true
                  raise: ${"Unknown recommendation:" + recommendResponse.body}
          - Buy Stock:
              call: http.post
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/BuyStock"}
                auth:
                  type: OIDC
                body:
                  action: ${recommendResponse.body}
              result: message
          - Sell Stock:
              call: http.post
              args:
                url: ${"https://" + region + "-" + projectId + ".cloudfunctions.net/SellStock"}
                auth:
                  type: OIDC
                body:
                  action: ${recommendResponse.body}
              result: message
          - Report Result:
              call: googleapis.pubsub.v1.projects.topics.publish
              args:
                topic: ${"projects/" + projectId + "/topics/" + topic}
                body:
                  messages:
                  - data: '${base64.encode(json.encode(message))}'
              next: end
      ...

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

    Sostituisci quanto segue:

    • LOCATION: una regione Google Cloud supportata. Ad esempio: us-central1.
    • PUBSUB_TOPIC_NAME: il nome del tuo argomento Pub/Sub. Ad esempio, my_stock_example.
  3. Esegui il deployment e 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 usare 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 dalla sottoscrizione 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