What are serverless workflows?
There are no shortage of workflow specifications: open source and commercial, services, platforms and software. Approaches have evolved rapidly with cloud-native development, microservice orchestration and serverless functions. The CNCF (Cloud Native Computing Foundation) sought to solve this problem with a vendor-neutral, open-source specification: serverless workflow.
The Serverless Workflow is a Domain Specific Language (DSL) for defining workflow logic. It decouples the definition of your workflow from the implementation (the runtime), allowing you to write your business logic once and run it on any cloud or platform. Serverless workflows are designed to be transportable and interoperable.
Why do we need them?
Business logic within complex systems and interconnectivity between microservices are often built using either GRPC or REST APIs for internal calls. For simple use cases this works, but once you start orchestrating flows that depend on multiple services to do the actual work (notify, create, modify etc.) if a part of that workflow fails recovering from failed state becomes increasingly challenging. How do we notify up-stream and down-stream components of this failure to rollback changes? Can we guarantee different teams responsible for different services are co-ordinated to support these capabilities?
Without a dedicated orchestration layer, spaghetti code is almost guaranteed: workflow logic will end up directly embedded into functions or services. This leads to tight coupling, difficult debugging, and a lack of visibility into the overall business process and general all round misery, unhappiness and compounding complexity.
The Serverless Workflows DSL provides a standard way to support:
- Orchestration
Complex chains of events and service calls. - Portability
Avoid vendor lock-in by using a standard specification rather than proprietary tools like AWS Step Functions or Azure Logic Apps. - Standardisation
Use a common format (YAML or JSON) that developers across different teams and organizations can understand.
How? Meet the DSL (Domain Specific Language)
Serverless Workflows are defined using a declarative YAML or JSON syntax. A workflow definition typically consists of three main parts:
- Document
Metadata about the workflow (ID, version, name). - Use
Definitions of reusable resources like functions, events, and secrets. - Do
The control flow logic, defined as a sequence of states. Including events and sub-workflows
Anatomy of a Workflow
Let's take a look at a simple "Hello World" example of a Serverless Workflow:
document:
dsl: "1.0.0-alpha5"
namespace: "thand-test"
name: "hello-world"
version: "1.0.0"
do:
- greet:
set:
greeting: ${ "Hello, " + (.name // "World") + "!" }
In this example, the primary workflow sets and outputs “Hello World”. What's cool about this example is a JSON greeting output: we can use simply use jq to expressively take the name from the input and place it in our output string. Otherwise, use World. More on that later.
Serverless workflow Features
Event-Driven Architecture
Serverless Workflow is designed from the ground up to be event-driven. It natively supports CloudEvents, allowing workflows to be triggered by events (e.g., a file upload, a user signup) and can emit events during execution.
Advanced Control Flow
The DSL supports complex logic beyond simple sequences:
- Switch
If/else logic to branch execution paths. - Parallel
Execute multiple branches concurrently. - Foreach
Iterate over a dataset.
Error Handling
In distributed systems, failure is inevitable and expected. The specification includes robust error handling mechanisms like `onErrors` and `retries`, allowing you to define backoff strategies and fallback logic directly in the workflow definition.
Task Types
Serverless Workflow defines a rich set of tasks to control the flow of execution. Here is how common concepts map to the specification:
- CALL
The workhorse of the workflow. It executes a specified function, such as calling a REST API (HTTP), a gRPC service, or an OpenAPI operation. - DO
Executes a sequence of subtasks. This is useful for grouping actions together. - EMIT
Publishes events to event brokers or messaging systems, enabling event-driven communication. - FOR
Iterates over a collection of data, executing a set of actions for each item. - FORK
Splits execution into multiple concurrent branches, waiting for all (or some) to complete before proceeding. - SWITCH
Evaluates conditions to determine the next state transition (If/Else logic). - LISTEN
Waits for external events to occur before proceeding. - RUN
Executes external processes like containers, shell commands, scripts, or other workflows.
Data Manipulation with jq
Serverless Workflow relies heavily on jq (or JSONPath) to manipulate data as it flows between states. This allows you to transform inputs and outputs without writing custom code.
- Input Filtering
Use the `input` property with a `jq` expression to select only the necessary parts of the incoming data for the current task. - Output Filtering
Use the `output` property with a `jq` expression to shape the data passed to the next task. - Expressions
You can use `jq` expressions within your workflow definition (e.g., `${ .user.id }`) to dynamically reference data in function arguments or state transitions.
Workflow Types & Patterns
Understanding the different types of workflows is key to leveraging the full power of the specification.
The SDK
For Go developers, the Serverless Workflow Go SDK is the starting point. It provides a comprehensive library for: Parsing, Validation and Diagram Generation of workflows.
While the SDK is excellent for working with the definitions, it is not a full-featured runtime. It can execute simple workflows in-memory, but it lacks the durability required for long-running business processes, or handling signals. At Thand, we handle this by executing workflows with Temporal.
Thand - Durable Execution with Temporal
Thand supports complex authorisation workflows, which - as you can imagine - makes extensive use of pre-defined approval workflows. The Thand agent leverages the serverless workflow SDK to provide a production-grade runtime for Serverless Workflows, backed by Temporal.io.
Why Temporal?
Temporal is a durable execution platform that ensures your workflows run to completion, even in the presence of failures. By mapping Serverless Workflow definitions to Temporal workflows, Thand offers:
- Durability
If your service crashes or restarts, the workflow resumes exactly where it left off. State is persisted automatically. - Long-Running Processes
Workflows can sleep for days, wait for human approval, or listen for external signals without consuming resources. - Signaling
You can interact with running workflows. For example, you can "signal" a workflow to update its state or trigger a new path (e.g., an admin approving a request). - Scalability
Temporal handles the heavy lifting of distributing workflow execution across a cluster. - Scheduling
Temporal handles the scheduling of workflows for a given point in time.
The Thand SDK
With the Thand SDK, you can define your business logic using the standard Serverless Workflow DSL, but execute it with the power of Temporal. This gives you the best of both worlds: the portability and readability of a standard spec, with the reliability and power of a world-class orchestration engine.
For example, we try and make second-person authorisation as simple as modern 2fa, so handling a complex approval process involving emails, Slack notifications, and timeouts becomes a matter of defining the states in YAML. Thand and Temporal ensure execution (grants or revocation of access, or monitoring of activity) happen consistently: signals are received and processed correctly, no matter how long the user takes to respond or how long access is granted.
Ready to get started?
Check out the Serverless Workflow Specification and the Thand Documentation to learn more.