❯ Guillaume Laforge

Orchestrating microservices with Google Cloud Workflows

The trend toward splitting a monolith into fine-grained loosely-coupled microservices has its merits. It allows us to scale parts of an application more easily. Teams become more effective on their focused perimeter. However, in a chain or graph of services interacting with each other via message buses or other eventing mechanisms, it becomes difficult to understand when things start to break. Your business processes spanning those services are in limbo. Here starts detective work to find out how to get back on track.

Choreography: like a bunch of dancers on the floor composing a ballet. Loosely-coupled microservices compose business processes without really being aware of each other, casually interacting by receiving and sending messages or events.

Orchestration: more like a conductor of an orchestra who directs musicians and their instruments to play each part. The approach of using a higher level solution that purposefully invokes and tracks each individual service, enables developers to know what the current state of a business process is.

Both approaches have their pros and cons. The loosely-coupled aspects of choreography certainly enables agility. But business processes are harder to follow. Although orchestration adds a single-point-of-failure with its orchestrator tying all the pieces together, it brings clarity in the spaghetti of myriads of microservices.

In addition to GCP’s existing messaging (Cloud Pub/Sub) and eventing solutions (Eventarc) for your service choreography, the newly launched product Cloud Workflows  is tackling the orchestration approach.

Cloud Workflows is a scalable fully-managed serverless system that automates and coordinates services, takes care of error handling and retries on failure, and tells you if the overall process has finished.

In this short video, during the “demo derby” at Google Cloud Next OnAir, I had the chance to present a demo of Cloud Workflows, with some concrete examples:

In this video, I started with the proverbial Hello World, using the Yaml syntax for defining workflows:

- hello:
    return: "Hello from Cloud Workflows!"

I defined a hello step, whose sole purpose is to return a string, as the result of its execution.

Next, I showed that workflow definitions can take arguments, and also return values thanks to more complex expressions:

main:
    params: [args]
    steps:
        - returnGreeting:
            return: ${"Hello " + args.first + " " + args.last}

Cloud Workflows is able to invoke any HTTP-based service (and supports OAuth2 and OIDC), whether in Google Cloud or outside (on premises, or other servers). Here, I invoke 2 Cloud Functions:

- getRandomNumber:
    call: http.get
    args:
        url: https://us-central1-myprj.cloudfunctions.net/randomNumber
    result: randomNumber
- getNthPoemVerse:
    call: http.get
    args:
        url: https://us-central1-myprj.cloudfunctions.net/theCatPoem
        query:
            nth: ${randomNumber.body.number}
    result: randomVerse
- returnOutput:
    return: ${randomVerse.body}

The getRandomNumber step calls a function that returns a random number with an HTTP GET, and stores the result of that invocation in the randomNumber variable.

The getNthPoemVerse calls another function that takes a query parameter, which is found in the randomNumber variable which holds the result of the previous function invocation.

The returnOutput step then returns the resulting value.

My fourth example shows variable assignment and conditional switches in action:

- getRandomNumber:
    call: http.get
    args:
        url: https://us-central1-myprj.cloudfunctions.net/randomNumber
    result: randomNumber
- assign_vars:
    assign:
        - number: ${int(randomNumber.body.number)}
- conditionalSwitch:
    switch:
        - condition: ${number < 33}
          next: low
        - condition: ${number < 66}
          next: medium
    next: high
- low:
    return: ${"That's pretty small! " + string(number)}
- medium:
    return: ${"Hmm, okay, an average number. " + string(number)}
- high:
    return: ${"It's a big number! " + string(number)}

Reusing the random function from the previous example, notice how variables are assigned, and how to create a switch with multiple conditions, as well as showing how to redirect the execution of the workflow to different steps, depending on the outcome of the switch.

But there’s really more to this! You can double check the syntax reference, to see all the constructs you can use in your workflow definitions.

Summary

Cloud Workflows:

  • Orchestrate Google Cloud and HTTP-based API services into serverless workflows
  • Automate complex processes
  • Fully managed service requires no infrastructure or capacity planning
  • Fast scalability supports scaling down to zero and pay-per-use pricing model

In terms of features:

  • Reliable workflow execution
  • Built-in error handling
  • Passing variable values between workflow steps
  • Built-in authentication for Google Cloud products
  • Low latency of execution
  • Support for external API calls
  • Built-in decisions and conditional step executions
  • Cloud Logging

If you want to get started with Cloud Workflows, you can head over to this hands-on codelabs from my colleague Mete Atamel. Learn more by watching this longer video by Product Manager Filip Knapik who dives into Cloud Workflows. In upcoming articles, we’ll come back to Workflows into more details, diving into some more advanced features, or how to migrate a choreographed example, into an orchestrated one. So, stay tuned!