Why Cadence?
Cadence® is an open source workflow orchestration service. It is a scalable, fault-tolerant, and developer focused platform that centralizes business logic and allows you to build complex workflows that integrate with your distributed service architecture.
We are seeing strong interest in our Cadence managed service offering and the customer base is growing steadily.
Instaclustr believes Cadence is a project with a bright future, an active community, and is frequently updated to incorporate a host of new features.
In April 2022, Instaclustr released our Cadence Managed Service, with full production SLA’s, 24×7 support, and streamlined cluster creation. It’s important to get feedback on any new service that is launched, so we are taking what we learn from our customers and improving it constantly. We are also actively contributing back to the Cadence project so that the community can benefit from our shared experiences.
In 2016, the Temporal project was forked from Cadence and is being maintained by some ex-Cadence developers. Since then, Temporal announced that they have ceased supporting the Cadence project. Some people interpreted this to mean that the Cadence project was replaced. This is not the case; the Cadence project announced a long term commitment and support to Cadence, driven primarily by a team at Uber, and Instaclustr is working in a partnership with them to grow the project.
Let’s Start Migrating
As of today, the projects have begun to drift apart slowly, but the client SDK’s are still very similar. We know there is a section of the community who are running Temporal and are interested in trying Cadence, but are not sure how much work it will take to migrate their existing activities and workflows.
Migrating is a 2-step process:
- First you will need a Cadence cluster—for that we can use the Instaclustr managed service.
- Second you will need to convert your client code to use the Cadence client SDK.
Step 2 is the focus for this article, and our example will be comparing the Java SDK.
The Orders Processing Workflow
Before we get started, let’s quickly define the workflow we are converting.
Here is the design of our example—a simple order processing workflow.
Let’s imagine an online store which generates orders and sends them to a processing backend.
When an order is generated, the following steps are taken by the workflow:
Check if the order is in stock
- If it’s not:
- Get the estimated restock date
- Notify the customer of the delay
- Wait for restock
- Start the order process again
- If it is in stock
- Package and send the order to the nominated address
- Notify the customer of pending delivery with a tracking reference
- Complete
We can visualize the workflow like this:
Fig 1: Order workflow
As we can see it’s a simple workflow with a single decision and an optional loop, depending on if the item is in stock, and a possible wait.
Demonstration Pull Request
We have created a public repository on github, and opened a pull request to show the changes that our project would require. The base project is our workflow developed to run on the Temporal SDK, and the pull request is submitting the changes required for the Cadence SDK.
The project includes the client code to start a workflow, activity and workflow code to run it, and common code shared across both projects.
You can view the pull request here: https://github.com/johndelcastillo/orders-demo/pull/1/files
Worker Project
In both Temporal and Cadence the worker is responsible for executing the workflow and activity logic. Here is a folder comparison to see which files changed in our project, the files with changes are in orange.
Change the Dependencies
The first thing is to change our dependencies and add the Cadence library.
In our above project, it’s the gradle config build.gradle.kts.
Maven
Update your pom.xml
1 2 3 4 5 |
<dependency> <groupId>com.uber.cadence</groupId> <artifactId>cadence-client</artifactId> <version>3.6.2</version> </dependency> |
Gradle
Update your build.gradle
1 |
compile group: 'com.uber.cadence', name: 'cadence-client', version: '3.6.2' |
Domain Objects
Our domain objects are passed around as parameters and return values from activities.
Moving from Temporal to Cadence, we can remove the annotations that are used by the Jackson json engine.
Activity and Workflow Interfaces
These interface files are almost identical, the only difference is Temporal requires an additional annotation on the interface that we don’t need for Cadence.
Activity Implementation
No changes!
It certainly may depend on how you organize your solution, but in our case since the Cadence specific code is abstracted away by the interfaces, we can port it across directly.
Workflow Implementation
Again, barely any change between these two files. Both Temporal and Cadence require configuring an activity stub and they differ slightly, but not much.
The workflow logic comes across without any change, including calling the Workflow.sleep and Workflow.continueAsNew.
Worker Startup
A few changes here, the primary difference is in how clients are configured.
The Temporal project renamed a few paradigms (domain, task lists) when they forked, but functionally they are the same thing and we can keep our config values as they are.
The remaining code to register the worker and implementation classes remains unchanged.
Client Project
Client code is normally part of a larger application, but this example still represents the scope of changes that are required.
Change the Dependencies
Same as the worker code, swap out Temporal to Cadence.
Maven
Update your pom.xml
1 2 3 4 5 |
<dependency> <groupId>com.uber.cadence</groupId> <artifactId>cadence-client</artifactId> <version>3.6.2</version> </dependency> |
Gradle
Update your build.gradle
1 |
compile group: 'com.uber.cadence', name: 'cadence-client', version: '3.6.2' |
Client
Finally, here is the client code side-by-side. Very similar to setting up the worker, we need to adjust our connection code to update it from the Temporal SDK to Cadence.
Once we have our clients configured, the remaining code to create the workflow stub and start the workflow is identical.
Finishing Up
We can see the amount of change required to convert this project is small and straightforward. Since the main workflow operators and commands are like-for-like, even a large activity and workflow implementation should convert across with little to no changes.
The connectivity code does need updating, but we can see that those changes are small and understandable.
We hope this example encourages developers out there to try switching from Temporal to Cadence, and get the benefits of the open source community that has grown around the Cadence project.
You can also sign up for a Cadence free trial and let Instaclustr manage the cluster for you, allowing you to build your next great workflow!