How to Migrate to the Open-Source Cadence Workflow
The fault-tolerant, stateful code platform is fully open source; here's how to make the migration, with a step-by-step example.
Join the DZone community and get the full member experience.
Join For FreeCadence 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.
Developers face steep difficulty in building modern high-scale distributed applications, which require them to wrangle long-running business processes, internal services, and third-party APIs to make them play well together. Designing those convoluted interactions forces developers to solve puzzles and carefully build numerous connections, with complex states to track, responses to asynchronous events to prepare, and communications to establish with external dependencies that often aren’t as reliable as hoped.
Developers normally answer these challenges by meeting complexity with complexity, putting together sprawling systems that rig up stateless services, databases, retry algorithms, and job scheduling queues to ensure the application can deliver its functionality. However, that monstrous complexity creates major issues when something goes wrong. Depending on unreliable distributed components is a recipe for availability issues. The business logic of these systems is buried under their own tremendous complexity, making remediation of those issues all the more difficult and time-consuming. From a productivity perspective, developers must often turn their focus to keeping these elaborate systems in operation, killing momentum on any other forward-looking projects.
Solutions like Cadence and Temporal exist to eliminate those hardships. Available as free and open-source software, these solutions abstract away the difficult complexity of creating high-scale distributed applications by storing the full application state in virtual memory, and catching up and replaying any interrupted workflows via that stored state.
How to Migrate to Open-Source Cadence From Temporal
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.
As of today, the projects have begun to drift apart slowly, but the client SDKs 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 two-step process:
- First, you will need a Cadence cluster — for this example, 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 of 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 — in this case, a simple order processing workflow.
Let’s imagine an online store that 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:
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
<dependency>
<groupId>com.uber.cadence</groupId>
<artifactId>cadence-client</artifactId>
<version>3.6.2</version>
</dependency>
Gradle
Update your build.gradle
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
<dependency>
<groupId>com.uber.cadence</groupId>
<artifactId>cadence-client</artifactId>
<version>3.6.2</version>
</dependency>
Gradle
Update your build.gradle
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.
I 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.
Opinions expressed by DZone contributors are their own.
Comments