Kafka + Cadence + WebSockets + Angular: managing event-driven microservices state with Uber Cadence
Published: 2020-03-17 17:42:40

In the the previous post of the _**Event-driven microservices with Kafka**_ series (see [here](https://dev.to/victorgil/kafka-websockets-angular-event-driven-microservices-all-the-way-to-the-frontend-12aa)), I showed how to extend the asynchronous event-driven communication all the way from Kafka to the Web frontend passing through the Java backend.  

In that proof of concept application which processes money transfers, one Kafka topic is used to receive incoming transfer messages and a second topic is used to store the account balances state (no need of a database) and also to broadcast changes (i.e., to push notifications from the backend to the frontend).  

The first topic (called "_transfers_") and the second topic (called "_account-balances_") are connected through Kafka Streams.  
  
## Uber Cadence
In this post we are bringing [Uber Cadence](https://cadenceworkflow.io/) into the mix to manage the state of the application (i.e., to keep the balance of the accounts updated), thus, **Cadence replaces Kafka Streams**.  
  
Cadence is an orchestration/workflow engine which unlike most of the other workflow engines out there (e.g., Zeebe, Camunda and many [others](https://github.com/mengjin001/awesome-workflow-engines)), does not rely on [BPMN](http://www.bpmn.org/) (nor on any other type of XML) to define a workflow.  
It uses regular programming languages such as Go and Java instead, which is a huge advantage as eloquently explained by Cadence's lead developer in [this comment](https://medium.com/@mfateev/i-absolutely-agree-that-zeebe-is-the-only-cloud-native-and-scalable-solution-in-bpmn-space-9bfa549d635c).  
  
It is out of the scope of this post to provide a detailed description or an introduction to Cadence, you are encouraged to perform your own (even if superficial) research and also watch [the companion video for this post](https://youtu.be/LKfZAFx56kI) but I will mention its main advantages:
- It makes your application easily scalable
- It hugely simplifies the error handling
- It comes with an admin Web UI and CLI
  
In short, it takes care of most of the heavy lifting inherent to a distributed application. 
  
## Enhanced PoC application
Let's go trough the data flow to get an overview of the application functionality.  
  
A new service called [Cadence transfers recording service](https://github.com/VictorGil/cadence_transfers_recording_service) listens for incoming transfer messages on a Kafka topic.  
  
If the message represents the act of opening a new account, the service creates a new [workflow](https://cadenceworkflow.io/docs/03_concepts/01_workflows) by using the corresponding Cadence Java client API [method](https://github.com/VictorGil/cadence_transfers_recording_service/blob/master/src/main/java/net/devaction/cadence/transfersrecordingservice/processor/TransferProcessor.java#L89).  
The Cadence server will assign the execution of the new workflow to one of the previously started Cadence workers. One important detail to note is that the id of the workflow matches the account id, i.e., there is one workflow per account.  
  
If the incoming Kafka message represents a money transfer which changes the balance of an existing account, the Cadence transfers recording service calls the [required method](https://github.com/VictorGil/cadence_transfers_recording_service/blob/master/src/main/java/net/devaction/cadence/transfersrecordingservice/processor/TransferProcessor.java#L70) (which must be annotated with [@SignalMethod](https://github.com/VictorGil/account_balance_workflow_api/blob/fc5766f7d93237b9d6973391a2c8548fa7352b72/src/main/java/net/devaction/cadence/accountbalanceworkflow/AccountBalanceWorkflow.java#L24)) on the workflow whose id matches the account id.  
That triggers the remote execution of the code on one of the Cadence workers, which after updating the value of the account balance as required, will send a Kafka message to the "_account-balances_" topic to announce the event.  
  
Next, the "_transfers websockets_" service will pull that message from the "_account-balances_" Kafka topic and broadcast it to the interested Angular Web clients through websockets.  
  
In addition to this asynchronous/push communication, an Angular client may query the "_transfers websockets_" service synchronously to get the current balance or the history of an account (i.e., the list of transfers for that account).  
The "_transfers websockets_" service, in order to fullfill those requests, will query the Cadence server by calling the corresponding method which must be annotated with [@QueryMethod](https://github.com/VictorGil/account_balance_workflow_api/blob/fc5766f7d93237b9d6973391a2c8548fa7352b72/src/main/java/net/devaction/cadence/accountbalanceworkflow/AccountBalanceWorkflow.java#L29).  
  
## Diagram
This is a high-level diagram of the PoC application, I am sorry if it looks a little messy, graphic design is not my strongest skill but it should help you to get an overview of the components and their interactions.
    
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/buj21ot4j9h9s651qnfs.png)
  
  
## See it in action
{% youtube LKfZAFx56kI %}

## Source code repositories
https://github.com/VictorGil/cadence_transfers_recording_service
https://github.com/VictorGil/account_balance_workflow_api
https://github.com/VictorGil/transfers_websockets_service 
https://github.com/VictorGil/transfers_frontend 
https://github.com/VictorGil/transfers_recording_service 
https://github.com/VictorGil/transfers_api 
https://github.com/VictorGil/kafka_util