What is Rumi Core
Rumi is a platform that enables microservice based applications to be to easily built, run and managed. A Rumi microservice is a lightweight, stateful, fault tolerant and horizontally scalable message processor. It stores read-write state as Java objects in local memory and durably persisted in a fault tolerant manner and collaborates with other microservices using transactional, fire-n-forget message passing.
A Rumi microservice is powered by the Rumi runtime. Application developers implement business logic in message handlers. The Rumi runtime uses configuration information to connect and subscribe to message streams of interest on a messaging fabric. It dispatches inbound messages to the application message handlers, the handlers execute business logic by invoking read-write operations on state and send outbound messages to downstream apps. Rumi presents the state and messages to the microservice logic in the form of POJOs enabling the microservice logic to perform read-write operations on state and messages via simple getter and setter methods on the state/message objects. Rumi ensures that these set/get operations execute at memory speeds, all microservice state changes are journaled in a replication manner and the application message handlers are invoked in an exactly once, fully fault tolerant and horizontally scalable manner.
A Simple Microservice
Lets say, for example, a developer would like to write a microservice that performs the following
Maintain a counter in its state
Receive a message, update the counter with the value in the message and send an outbound message with the updated counter value
Furthermore, the developer needs to ensure that the system continues to operate without service interruption in the face of process, network, machine or data center failures. Rumi makes it very simple to author such a microservice. To do so, a developer would do the following:
Model the microservice data and messages in XML: In the above microservice, the state is an object that contains a single counter field, the inbound message contains a field whose value needs to be added to the state counter and the outbound message contains a field with the updated value of the state counter.
Inject the Rumi code generator into the build process: Application logic only works with POJOs and so the modelled state and messages need to be converted to POJOs. This is done using the Rumi code generator. Rumi integrates with build tools such as Maven, ANT and Gradle to enable the code generators to be injected into the appropriate stage in the build cycle.. At runtime, the microservice logic works with these generated objects, not the XML.
Author a message handler: The Rumi runtime invokes the message handler on receipt of an inbound message. When invoked, Rumi presents the handler with the store root object and the inbound message as POJOs. The handler reads the value from the inbound message, updates the counter field in its state and then creates, populates and sends an outbound message POJO populated with the updated counter value.
That's it. All the non-functional aspects of such a microservice, including lifecycle management, messaging connectivity, message encoding/decoding, in-memory data storage, message and state journaling and persistence, cluster replication and consensus management and linear scaling are all transparently taken care of by the Rumi runtime.
Microservice Data Store
A Rumi microservice data store is modeled using XML converted to POJOs by the Rumi code generator. The following is the model for the store for the above microservice. The model defines a state tree with a single root Repository object that contains a long field named counter that is used to hold the running counter.
<model>
...
<entities>
<entity name="Repository">
<field name="counter" type="Long"/>
</entity>
</entities>
</model>The Store
The store of a Rumi microservice is structured as an object tree. Each node of the tree can be an individual object or an object collection with the field type system equivalent to the Java type system. This enables arbitrarily complex state models.
State Replication vs Event Sourcing
Rumi supports two different types of microservices - State Replicated and Event Sourced. The above microservice is an example of a State Replication microservice that models state and uses the generated POJOs to store state. Event Sourced microservices, on the other hand, do not model state as XML and, instead, store their state in regular POJOs. This categorization is based on how the microservice manages consensus between the various microservice cluster members. State replication microservice establish cluster consensus by hot replicating changes to state to all cluster members while Event Sourced microservice establish consensus by replaying inbound messages on all cluster members.
Application Messages
Rumi messages are also modeled using XML converted to POJOs by the Rumi code generator. The following is the model for the inbound and outbound messages processed by the above microservice.
Write Application Logic
From the point of view of an application developer, the business logic of a microservice is coded as message handlers. When a message arrives, the Rumi runtime invokes the appropriate message handler, identified by message signature, with the message POJO and the POJO of the root object of the store. Between the inbound message and the state tree, the message handler has all that it needs to implement its business logic.
The below is the InMessage message handler for the above microservice.
That's it! Thats all the developer has to do to produce a fault tolerant and highly performant stateful message processor. In essence, Rumi implements all the non-functional aspects of a stateful, message driven microservice leaving the developer to focus only on the business logic and domain. In doing so, it enables highly performance, fault tolerant and linearly scalable microservice based applications to be built, deployed and managed very easily.
Last updated

