Simplified Workflow Authoring
Focus on the business logic of what you want to achieve rather than focusing on how to use Temporal.
Consistency and Reusability
Zigflow enforces consistent patterns across your Temporal estate, allowing you to reuse definitions, share components and make your entry to the world of Temporal easier.
Low Code
Get all the benefits of Temporal - reliability, speed and consistency - without having to learn the nuances of writing code
Zigflow is a Temporal DSL — a domain-specific language for defining and running Temporal workflows declaratively.
User-Friendly DSL: Temporal Made Simple
A collection of examples of how to use Zigflow's Temporal DSL to create Temporal workflows. These can be found in the GitHub repo.
- Child Workflows
- Custom Search Attributes
- External Calls
- For
- Heartbeat
- Query Listeners
- Scheduling
- Signal Listeners
- Update Listeners
Child Workflows
Define multiple workflows and call a child workflow from a parent
document:
dsl: 1.0.0
namespace: zigflow
name: childWorkflow
version: 0.0.1
title: Child Workflows
summary: Define multiple workflows and call a child workflow from a parent
timeout:
after:
minutes: 1
do:
- parentWorkflow:
do:
- wait:
wait:
seconds: 5
# Call child workflow as a single workflow - this will be run synchronously
- callChildWorkflow1:
run:
workflow:
name: child-workflow1
namespace: default
version: 0.0.0
# Do a fan-out child workflow - this will be run asynchronously
- fanOut:
fork:
compete: false
branches:
- callWorkflow1:
run:
workflow:
name: child-workflow1
namespace: default
version: 0.0.0
- callWorkflow2:
run:
workflow:
name: child-workflow2
namespace: default
version: 0.0.0
- wait:
output:
as:
completed: true
wait:
seconds: 5
- child-workflow1:
do:
- wait:
wait:
seconds: 10
- child-workflow2:
do:
- wait:
wait:
seconds: 3
Custom Search Attributes
How to add custom search attribute data into your Temporal workflows
document:
dsl: 1.0.0
namespace: zigflow
name: searchAttributes # Workflow name
version: 0.0.1
title: Custom Search Attributes
summary: How to add custom search attribute data into your Temporal workflows
input:
schema:
format: json
document:
type: object
required:
- userId
properties:
userId:
type: number
timeout:
after:
minutes: 1
do:
- wait:
metadata:
searchAttributes:
waitTime:
type: int
value: 5
wait:
seconds: 5
- getUser:
call: http
metadata:
# The search attributes must be configured in your Temporal service - with great power comes great responsibility
searchAttributes:
hello:
type: text
value: world
call:
type: text
value: ${ $data.task.name }
userId:
type: int
value: ${ $input.userId }
with:
method: get
endpoint: ${ "https://jsonplaceholder.typicode.com/users/" + ($input.userId | tostring) }
- wait:
metadata:
searchAttributes:
waitTime:
type: int
value: 3
wait:
seconds: 3
External Calls
An example of how to use Zigflow to make external gRPC and HTTP calls
document:
dsl: 1.0.0
namespace: zigflow
name: external-calls
version: 0.0.1
title: External Calls
summary: An example of how to use Zigflow to make external gRPC and HTTP calls
do:
- fork:
fork:
compete: false
branches:
- grpc:
call: grpc
with:
proto:
endpoint: file:///go/app/examples/external-calls/grpc/basic/proto/basic/v1/basic.proto
service:
name: providers.v1.BasicService
host: grpc
port: 3000
method: Command1
arguments:
input: ${ $env.GRPC_INPUT }
- http:
call: http
with:
method: get
endpoint: https://jsonplaceholder.typicode.com/users/3
For
How to use the for loop task
document:
dsl: 1.0.0
namespace: zigflow
name: for-loop
version: 0.0.1
title: For
summary: How to use the for loop task
input:
schema:
format: json
document:
type: object
required:
- map
- data
properties:
map:
type: object
required:
- key1
- key2
- key3
properties:
key1:
type: string
key2:
type: number
key3:
type: boolean
data:
type: array
items:
type: object
required:
- userId
properties:
userId:
type: number
do:
# Iterate over the map object
- forTaskMap:
export:
as: '${ $context + { forTaskMap: . } }'
for:
in: ${ $input.map }
do:
- setData:
export:
as: ${ . }
set:
key: "${ \"hello: \" + $data.index }"
value: ${ $data.item }
- wait:
output:
as: ${ $context }
wait:
seconds: 2
# Iterate over the data array
- forTaskArray:
export:
as: '${ $context + { forTaskArray: . } }'
for:
each: item
in: ${ $input.data }
at: index
# while: ${ $data.item.userId != 4 } # If this returns false, it will cut the iteration
do:
# Each iteration will run these tasks in order
- setData:
export:
as: ${ . }
set:
userId: ${ $data.item.userId } # Get the userId for this iteration
id: ${ $data.index } # Get the key
processed: true
- wait:
output:
as: ${ $context }
wait:
seconds: 1
- forTaskNumber:
output:
as: '${ $context + { forTaskNumber: . } }'
for:
in: ${ 5 }
do:
- setData:
export:
as: ${ . }
set:
number: ${ $data.item }
- wait:
output:
as: ${ $context }
wait:
seconds: 1
Heartbeat
Set [activity heartbeat](https://docs.temporal.io/encyclopedia/detecting-activity-failures#activity-heartbeat). Useful on long-running activities.
document:
dsl: 1.0.0
namespace: zigflow
name: heartbeat
version: 0.0.1
title: Heartbeat
summary: Set [activity heartbeat](https://docs.temporal.io/encyclopedia/detecting-activity-failures#activity-heartbeat). Useful on long-running activities.
do:
- longRunningActivity:
metadata:
# Trigger a heartbeat every 8 seconds - this MUST be less than your heartbeatTimeout
heartbeat:
seconds: 8
activityOptions:
# Set a heartbeat timeout of 10 seconds
heartbeatTimeout:
seconds: 10
run:
shell:
# Sleep for 30s - this will timeout if heartbeat doesn't run
command: sleep
arguments:
- "30"
Query Listeners
Listen for Temporal query events
document:
dsl: 1.0.0
namespace: zigflow
name: query
version: 0.0.1
title: Query Listeners
summary: Listen for Temporal query events
metadata:
# Acts as override to test out continue-as-new
# @link https://docs.temporal.io/develop/go/continue-as-new
canMaxHistoryLength: 5
do:
- queryState:
listen:
to:
one:
with:
# ID maps to the query name in Temporal
id: get_state
# Temporal query - used to make a non-blocking read request
type: query
# This data will be returned as-is
data:
id: ${ $data.id }
progressPercentage: ${ $data.progressPercentage }
status: ${ $data.status }
- createState:
output:
as:
data: ${ . }
set:
# Items created at top-level are persisted
id: ${ uuid }
status: not started
progressPercentage: 0
- wait:
wait:
seconds: 5
- updateState:
set:
progressPercentage: 33
status: running
- wait:
wait:
seconds: 5
- updateState:
set:
progressPercentage: 66
# status remains as "running" if it remains as top-level item
- wait:
wait:
seconds: 5
- stateComplete:
set:
progressPercentage: 100
status: finished
- wait:
wait:
seconds: 5
Scheduling
Schedule the tasks to be triggered automatically
document:
dsl: 1.0.0
namespace: zigflow
name: schedule
version: 0.0.1
title: Scheduling
summary: Schedule the tasks to be triggered automatically
metadata:
# Set the workflow name to trigger - this will either be the document.name or the Do task (see multiple-workflows example)
scheduleWorkflowName: schedule
# Optionally set the schedule ID name
scheduleId: some-schedule
# Optionally set any input for the workflow when triggered - this can receive envvars
scheduleInput:
- msg:
- hello
- world
envvars: ${ $env.EXAMPLE_ENVVAR }
timeout:
after:
minutes: 1
schedule:
# Every is supported as a Temporal interval - https://pkg.go.dev/go.temporal.io/sdk/client#ScheduleIntervalSpec
every:
minutes: 3
# Cron is supported as a Temporal cronjob - timezone is UTC
cron: "0 0 * * *"
do:
- wait:
wait:
seconds: 5
Signal Listeners
Listen for Temporal signal events
document:
dsl: 1.0.0
namespace: zigflow
name: signal
version: 0.0.1
title: Signal Listeners
summary: Listen for Temporal signal events
do:
- approveListener:
metadata:
timeout: 10s # Controls the AwaitWithTimeout timeout - defaults to 60s
listen:
to:
one:
with:
# ID maps to the signal name in Temporal - this blocks until received
id: approve
# Temporal signal - used to make write request
type: signal
acceptIf: ${ $data.approveListener }
- outputSignal:
export:
as: '${ $context + { response: . } }'
set:
# Get the data from the approveListener signal
signal: ${ $data.approveListener }
- wait:
output:
as: ${ $context }
wait:
seconds: 5
Update Listeners
Listen for Temporal update events
document:
dsl: 1.0.0
namespace: zigflow
name: updates
version: 0.0.1
title: Update Listeners
summary: Listen for Temporal update events
do:
- callDoctor:
metadata:
timeout: 10s # Controls the AwaitWithTimeout timeout - defaults to 60s
listen:
to:
# Only progress after every update received
all:
- with:
# ID maps to the update name in Temporal
id: temperature
# Temporal update - used to make read/write request
type: update
acceptIf: ${ $data.temperature > 38 }
- with:
id: bpm
type: update
acceptIf: ${ $data.bpm < 60 or $data.bpm > 100 }
- wait:
output:
as:
temperature: ${ $data.temperature }
bpm: ${ $data.bpm }
wait:
seconds: 10