how do you start a workflow from another workflow and retrieve the return value of called workflow

2.5k views Asked by At

I am testing google workflow and would like to call a workflow from another workflow but as a separate process (not a subworkflow)

I am able to start the execution but currently unable to retrieve the return value. I receive instead an instance of the execution:

{
     "argument": "null",
     "name": "projects/xxxxxxxxxxxx/locations/us-central1/workflows/child-workflow/executions/9fb4aa01-2585-42e7-a79f-cfb4b57b22d4",
     "startTime": "2020-12-09T01:38:07.073406981Z",
     "state": "ACTIVE",
     "workflowRevisionId": "000003-cf3"
 }

parent-workflow.yaml

main:
params: [args]

steps:
    
    - callChild:
        call: http.post
        args:
            url: 'https://workflowexecutions.googleapis.com/v1beta/projects/my-project/locations/us-central1/workflows/child-workflow/executions'
            auth: 
                type: OAuth2
                scope: 'https://www.googleapis.com/auth/cloud-platform'
        result: callresult
    
    - returnValue:
        return: ${callresult.body}

child-workflow.yaml:

 - getCurrentTime:
        call: http.get
        args:
            url: https://us-central1-workflowsample.cloudfunctions.net/datetime
        result: CurrentDateTime
    - readWikipedia:
        call: http.get
        args:
            url: https://en.wikipedia.org/w/api.php
            query:
                action: opensearch
                search: ${CurrentDateTime.body.dayOfTheWeek}
        result: WikiResult
    - returnOutput:
        return: ${WikiResult.body[1]}

also as an added question how can create a dynamic url from a variable. ${} doesn't seem to work there

2

There are 2 answers

2
Pentium10 On BEST ANSWER

As Executions are async API calls, you need to POLL for the workflow to see when finished.

You can have the following algorithm:

main:
  steps:  
    - callChild:
        call: http.post
        args:
            url: ${"https://workflowexecutions.googleapis.com/v1beta/projects/"+sys.get_env("GOOGLE_CLOUD_PROJECT_ID")+"/locations/us-central1/workflows/http_bitly_secrets/executions"}
            auth: 
                type: OAuth2
                scope: 'https://www.googleapis.com/auth/cloud-platform'
        result: workflow
    - waitExecution:
        call: CloudWorkflowsWaitExecution
        args:
          execution: ${workflow.body.name}
        result: workflow
    - returnValue:
        return: ${workflow}
CloudWorkflowsWaitExecution:
  params: [execution]
  steps:
    - init:
        assign:
          - i: 0
          - valid_states: ["ACTIVE","STATE_UNSPECIFIED"]
          - result: 
              state: ACTIVE
    - check_condition:
        switch:
          - condition: ${result.state in valid_states AND i<100}
            next: iterate
        next: exit_loop
    - iterate:
        steps:
          - sleep:
              call: sys.sleep
              args:
                seconds: 10
          - process_item:
              call: http.get
              args:
                url: ${"https://workflowexecutions.googleapis.com/v1beta/"+execution}
                auth:
                  type: OAuth2
              result: result
          - assign_loop:
              assign:
                - i: ${i+1}
                - result: ${result.body} 
        next: check_condition
    - exit_loop:
        return: ${result}

What you see here is that we have a CloudWorkflowsWaitExecution subworkflow which will loop 100 times at most, also has a 10 second delay, it will stop when the workflow has finished, and returns the result.

The output is:

argument: 'null'
endTime: '2020-12-09T13:00:11.099830035Z'
name: projects/985596417983/locations/us-central1/workflows/call_another_workflow/executions/05eeefb5-60bb-4b20-84bd-29f6338fa66b
result: '{"argument":"null","endTime":"2020-12-09T13:00:00.976951808Z","name":"projects/985596417983/locations/us-central1/workflows/http_bitly_secrets/executions/2f4b749c-4283-4c6b-b5c6-e04bbcd57230","result":"{\"archived\":false,\"created_at\":\"2020-10-17T11:12:31+0000\",\"custom_bitlinks\":[],\"deeplinks\":[],\"id\":\"j.mp/2SZaSQK\",\"link\":\"//<edited>/2SZaSQK\",\"long_url\":\"https://cloud.google.com/blog\",\"references\":{\"group\":\"https://api-ssl.bitly.com/v4/groups/Bg7eeADYBa9\"},\"tags\":[]}","startTime":"2020-12-09T13:00:00.577579042Z","state":"SUCCEEDED","workflowRevisionId":"000001-478"}'
startTime: '2020-12-09T13:00:00.353800247Z'
state: SUCCEEDED
workflowRevisionId: 000012-cb8

in the result there is a subkey that holds the results from the external Workflow execution.

0
Kris Braun On

The best method is now the workflows.executions.run helper method, which formats the request and blocks until the workflow execution has completed:

- run_execution:
    try:
      call: googleapis.workflowexecutions.v1.projects.locations.workflows.executions.run
      args:
        workflow_id: ${workflow}
        location: ${location}   # Defaults to current location
        project_id: ${project}  # Defaults to current project
        argument: ${arguments}  # Arguments could be specified inline as a map instead.
      result: r1
    except:
      as: e
      steps: ... # handle a failed execution