Using Workflows to connect services

Note: This content applies only to Cloud Run functions—formerly Cloud Functions (2nd gen).

For the 1st gen version of this document, see theWorkflows tutorial (1st gen).

This tutorial shows you how to use Workflows to link a series ofservices together. By connecting two public HTTP services usingCloud Run functions, an external REST API, and a privateCloud Run service, you can create a flexible, serverless application.

Objectives

In this tutorial, you use the Google Cloud CLI to create a single workflow,connecting one service at a time:

  1. Deploy two Cloud Run functions: the first function generates a random number, and then passes that number to the second function which multiplies it.
  2. Using Workflows, connect the two HTTP functions together. Execute the workflow and return a result that is then passed to an external API.
  3. Using Workflows, connect an external HTTP API that returns thelog for a given number. Execute the workflow and return a result that is then passed to a Cloud Run service.
  4. Deploy a Cloud Run service that allows authenticated access only. The service returns themath.floor for a given number.
  5. Using Workflows, connect the Cloud Run service, execute the entire workflow, and return a final result.

The following diagram shows both an overview of the process as well as avisualization of the final workflow:

Workflows visualization

Costs

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use thepricing calculator.

New Google Cloud users might be eligible for afree trial.

Before you begin

Security constraints defined by your organization might prevent you from completing the following steps. For troubleshooting information, seeDevelop applications in a constrained Google Cloud environment.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  4. Toinitialize the gcloud CLI, run the following command:

    gcloudinit
  5. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.
    • Create a Google Cloud project:

      gcloud projects createPROJECT_ID

      ReplacePROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set projectPROJECT_ID

      ReplacePROJECT_ID with your Google Cloud project name.

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Artifact Registry, Cloud Build, Cloud Run, Cloud Run functions, Cloud Storage, and Workflows APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enable permission.Learn how to grant roles.

    gcloudservicesenableartifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com cloudfunctions.googleapis.com storage.googleapis.com workflows.googleapis.com
  8. Install the Google Cloud CLI.

  9. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  10. Toinitialize the gcloud CLI, run the following command:

    gcloudinit
  11. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.
    • Create a Google Cloud project:

      gcloud projects createPROJECT_ID

      ReplacePROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set projectPROJECT_ID

      ReplacePROJECT_ID with your Google Cloud project name.

  12. Verify that billing is enabled for your Google Cloud project.

  13. Enable the Artifact Registry, Cloud Build, Cloud Run, Cloud Run functions, Cloud Storage, and Workflows APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enable permission.Learn how to grant roles.

    gcloudservicesenableartifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com cloudfunctions.googleapis.com storage.googleapis.com workflows.googleapis.com
  14. Update the Google Cloud CLI components:
    gcloudcomponentsupdate
  15. If you are running commands inside Cloud Shell, you are already authenticated with the gcloud CLI; otherwise, sign in using your account:
    gcloudauthlogin
  16. Set the default location used in this tutorial:
    gcloudconfigsetprojectPROJECT_IDexportREGION=REGIONgcloudconfigsetfunctions/region${REGION}gcloudconfigsetrun/region${REGION}gcloudconfigsetworkflows/location${REGION}

    ReplaceREGION with the supported Workflowslocation of your choice.

  17. If you are the project creator, you are granted thebasic Owner role(roles/owner). By default, this Identity and Access Management (IAM) roleincludes the permissions necessary for full access to most Google Cloudresources and you can skip this step.

    If you are not the project creator, required permissions must be granted onthe project to the appropriateprincipal. For example, a principal can bea Google Account (for end users) or a service account (for applications andcompute workloads). For more information, see theRoles and permissions pagefor your event destination.

    Required permissions

    To get the permissions that you need to complete the tutorial, ask your administrator to grant you the following IAM roles on your project:

    For more information about granting roles, seeManage access to projects, folders, and organizations.

    You might also be able to get the required permissions throughcustom roles or otherpredefined roles.

    Note:IAM basic roles might also contain permissions to complete the tutorial. You shouldn't grant basic roles in a production environment, but you can grant them in a development or test environment.
  18. When you deploy your workflow, you associate it with a specified serviceaccount. Create a service account for Workflows to use:
    exportSERVICE_ACCOUNT=workflows-sagcloudiamservice-accountscreate${SERVICE_ACCOUNT}
  19. All Cloud Run services are deployed privately by defaultand are only callable by Project Owners, Project Editors, Cloud RunAdmins, and Cloud Run Invokers. To allow the service account tocall an authenticated Cloud Run service, grant therun.invoker role to the Workflows service account:
    gcloudprojectsadd-iam-policy-bindingPROJECT_ID\--member"serviceAccount:${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com"\--role"roles/run.invoker"

Deploy the first Cloud Run functions

After receiving an HTTP request, this HTTP function generates a random numberbetween 1 and 100, and then returns the number in JSON format.

  1. Create a directory calledrandomgen and change to it:

    mkdir~/randomgencd~/randomgen
  2. Create a text file with the filenamemain.py that contains the followingPython code:

    importfunctions_frameworkimportrandomfromflaskimportjsonify@functions_framework.httpdefrandomgen(request):randomNum=random.randint(1,100)output={"random":randomNum}returnjsonify(output)
  3. To support a dependency on Flask for HTTP processing, create a text file forthe pip package manager. Give it the filenamerequirements.txt and add thefollowing:

    flask>=1.0.2functions-framework==3.0.0
  4. Deploy the function with an HTTP trigger, and allow unauthenticated access:

    gcloudfunctionsdeployrandomgen-function\--gen2\--runtimepython310\--entry-point=randomgen\--trigger-http\--allow-unauthenticated

    The function might take a few minutes to deploy. Alternatively, you canuse the Cloud Run functions interfacein the Google Cloud console to deploy the function.

  5. Once therandomgen function is deployed, you can confirm thehttpsTrigger.url property:

    gcloudfunctionsdescriberandomgen-function\--gen2\--format="value(serviceConfig.uri)"
  6. Save the URL. You will need to add it to your Workflow source file inlater exercises.

  7. You can try out the function with the following curl command:

    curl$(gcloudfunctionsdescriberandomgen-function\--gen2\--format="value(serviceConfig.uri)")

    A number is randomly generated and returned.

Deploy the second Cloud Run functions

After receiving an HTTP request, this HTTP function extracts theinput fromthe JSON body, multiplies it by 2, and returns the result in JSON format.

  1. Navigate back to your home directory:

    cd~
  2. Create a directory calledmultiply and change to it:

    mkdir~/multiplycd~/multiply
  3. Create a text file with the filenamemain.py that contains the followingPython code:

    importfunctions_frameworkfromflaskimportjsonify@functions_framework.httpdefmultiply(request):request_json=request.get_json()output={"multiplied":2*request_json['input']}returnjsonify(output)
  4. To support a dependency on Flask for HTTP processing, create a text file forthe pip package manager. Give it the filenamerequirements.txt and add thefollowing:

    flask>=1.0.2functions-framework==3.0.0
  5. Deploy the function with an HTTP trigger, and allow unauthenticated access:

    gcloudfunctionsdeploymultiply-function\--gen2\--runtimepython310\--entry-point=multiply\--trigger-http\--allow-unauthenticated

    The function might take a few minutes to deploy. Alternatively, you canuse the Cloud Run functions interfacein the Google Cloud console to deploy the function.

  6. Once themultiply function is deployed, you can confirm thehttpsTrigger.url property:

    gcloudfunctionsdescribemultiply-function\--gen2\--format="value(serviceConfig.uri)"
  7. Save the URL. You will need to add it to your Workflow source file inlater exercises.

  8. You can try out the function with the following curl command:

    curl-XPOSTMULTIPLY_FUNCTION_URL\-H"Authorization: Bearer$(gcloudauthprint-identity-token)"\-H"Content-Type: application/json"\-d'{"input": 5}'

    The number 10 should be returned.

Connect the two Cloud Run functions in a workflow

A workflow is made up of a series of steps described using theWorkflows syntax, which can be written in either YAML or JSONformat. This is the workflow's definition. For a detailed explanation, see theSyntax reference page.

  1. Navigate back to your home directory:

    cd~
  2. Create a text file with the filenameworkflow.yaml that contains the followingcontent:

    -randomgen_function:call:http.getargs:url:RANDOMGEN_FUNCTION_URLresult:randomgen_result-multiply_function:call:http.postargs:url:MULTIPLY_FUNCTION_URLbody:input:${randomgen_result.body.random}result:multiply_result-return_result:return:${multiply_result}

    This source file links the two HTTP functions together and returns a final result.

    Note: To make a request to a Cloud Run function that accepts onlyauthenticated calls, use OIDC to authenticate. For more information, seeMake authenticated requests from a workflow.
  3. After creating the workflow, you can deploy it, which makes it ready forexecution.

    gcloudworkflowsdeployWORKFLOW_NAME\--source=workflow.yaml\--service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com

    ReplaceWORKFLOW_NAME with a name for your workflow.

  4. Execute the workflow:

    gcloudworkflowsrunWORKFLOW_NAME

    An execution is a single run of the logic contained in a workflow's definition.All workflow executions are independent, and the rapid scaling ofWorkflows allows for a high number of concurrent executions.

    After the workflow is executed, the output should resemble the following:

    result: '{"body":{"multiplied":120},"code":200,"headers":{"Alt-Svc":"h3-29=\":443\";...startTime: '2021-05-05T14:17:39.135251700Z'state: SUCCEEDED...

Connect a public REST service in the workflow

Update your existing workflow and connect a public REST API(math.js)that can evaluate mathematical expressions. For example,curl https://api.mathjs.org/v4/?'expr=log(56)'.

Note that since you have deployed your workflow, you can also edit it throughtheWorkflows page in the Google Cloud console.

  1. Edit the source file for your workflow and replace it with the followingcontent:

    -randomgen_function:call:http.getargs:url:RANDOMGEN_FUNCTION_URLresult:randomgen_result-multiply_function:call:http.postargs:url:MULTIPLY_FUNCTION_URLbody:input:${randomgen_result.body.random}result:multiply_result-log_function:call:http.getargs:url:https://api.mathjs.org/v4/query:expr:${"log(" + string(multiply_result.body.multiplied) + ")"}result:log_result-return_result:return:${log_result}

    This links the external REST service to the Cloud Run functions,and returns a final result.

  2. Deploy the modified workflow:

    gcloudworkflowsdeployWORKFLOW_NAME\--source=workflow.yaml\--service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com

Deploy a Cloud Run service

Deploy a Cloud Run service that, after receiving an HTTPrequest, extractsinput from the JSON body, calculates itsmath.floor, andreturns the result.

  1. Create a directory calledfloor and change to it:

    mkdir~/floorcd~/floor
  2. Create a text file with the filenameapp.py that contains the followingPython code:

    importjsonimportloggingimportosimportmathfromflaskimportFlask,requestapp=Flask(__name__)@app.route('/',methods=['POST'])defhandle_post():content=json.loads(request.data)input=float(content['input'])returnf"{math.floor(input)}",200if__name__!='__main__':# Redirect Flask logs to Gunicorn logsgunicorn_logger=logging.getLogger('gunicorn.error')app.logger.handlers=gunicorn_logger.handlersapp.logger.setLevel(gunicorn_logger.level)app.logger.info('Service started...')else:app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT',8080)))

  3. In the same directory, create aDockerfile with the following content:

    # Use an official lightweight Python image.# https://hub.docker.com/_/pythonFROMpython:3.7-slim# Install production dependencies.RUNpipinstallFlaskgunicorn# Copy local code to the container image.WORKDIR/appCOPY..# Run the web service on container startup. Here we use the gunicorn# webserver, with one worker process and 8 threads.# For environments with multiple CPU cores, increase the number of workers# to be equal to the cores available.CMDexecgunicorn--bind0.0.0.0:8080--workers1--threads8app:app

  4. Create an Artifact Registry standard repository where you can store yourDocker container image:

    gcloudartifactsrepositoriescreateREPOSITORY\--repository-format=docker\--location=${REGION}

    ReplaceREPOSITORY with a unique name for therepository.

  5. Build the container image:

    exportSERVICE_NAME=floorgcloudbuildssubmit--tag${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}
  6. Deploy the container image to Cloud Run, ensuring that it onlyaccepts authenticated calls:

    gcloudrundeploy${SERVICE_NAME}\--image${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}:latest\--no-allow-unauthenticated

When you see the service URL, the deployment is complete. You will need tospecify that URL when updating the workflow definition.

Connect the Cloud Run service in the workflow

Update your existing workflow and specify the URL for the Cloud Runservice.

  1. Navigate back to your home directory:

    cd~
  2. Edit the source file for your workflow and replace it with the followingcontent:

    -randomgen_function:call:http.getargs:url:RANDOMGEN_FUNCTION_URLresult:randomgen_result-multiply_function:call:http.postargs:url:MULTIPLY_FUNCTION_URLbody:input:${randomgen_result.body.random}result:multiply_result-log_function:call:http.getargs:url:https://api.mathjs.org/v4/query:expr:${"log(" + string(multiply_result.body.multiplied) + ")"}result:log_result-floor_function:call:http.postargs:url:CLOUD_RUN_SERVICE_URLauth:type:OIDCbody:input:${log_result.body}result:floor_result-create_output_map:assign:-outputMap:randomResult:${randomgen_result}multiplyResult:${multiply_result}logResult:${log_result}floorResult:${floor_result}-return_output:return:${outputMap}
    • ReplaceRANDOMGEN_FUNCTION_URL with the URL of yourrandomgen function.
    • ReplaceMULTIPLY_FUNCTION_URL with the URL of yourmultiply function.
    • ReplaceCLOUD_RUN_SERVICE_URL with yourCloud Run service URL.

    This connects the Cloud Run service in the workflow. Notethat theauth key ensures that an authentication token is being passed inthe call to the Cloud Run service. For more information,seeMake authenticated requests from a workflow.

  3. Deploy the modified workflow:

    gcloudworkflowsdeployWORKFLOW_NAME\--source=workflow.yaml\--service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com
  4. Execute the final workflow:

    gcloudworkflowsrunWORKFLOW_NAME

    The output should resemble the following:

    result: '{"floorResult":{"body":"4","code":200  ...  "logResult":{"body":"4.02535169073515","code":200  ...  "multiplyResult":{"body":{"multiplied":56},"code":200  ...  "randomResult":{"body":{"random":28},"code":200  ...startTime: '2023-11-13T21:22:56.782669001Z'state: SUCCEEDED

Congratulations! You have deployed and executed a workflow that connects aseries of services together.

To create more complex workflows using expressions, conditional jumps,Base64 encoding or decoding, subworkflows, and more, refer to theWorkflows syntax referenceand theStandard library overview.

Clean up

If you created a new project for this tutorial,delete the project.If you used an existing project and want to keep it without the changes addedin this tutorial,delete resources created for the tutorial.

Delete the project

The easiest way to eliminate billing is to delete the project that you created for the tutorial.

To delete the project:

    Caution: Deleting a project has the following effects:
    • Everything in the project is deleted. If you used an existing project for the tasks in this document, when you delete it, you also delete any other work you've done in the project.
    • Custom project IDs are lost. When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs that use the project ID, such as anappspot.com URL, delete selected resources inside the project instead of deleting the whole project.

    If you plan to explore multiple architectures, tutorials, or quickstarts, reusing projects can help you avoid exceeding project quota limits.

  1. In the Google Cloud console, go to theManage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then clickDelete.
  3. In the dialog, type the project ID, and then clickShut down to delete the project.

Delete tutorial resources

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.