The following are the ingredients of a Rumi application that a microservice developer works with:
XML Models
A message model
One message model shared across multiple microservices
State models (optional)
One state model per microservice
User code
The HA Policy Declarer
Lifecycle Methods
Microservice Initializers
Message Filters & Handlers
Platform configuration
Message & State Models
The Application Data Modeler (ADM) component of Rumi employes an XML-based modeling language to define application messages and microservice stores. These XML models are inputs for the Rumi code generator, which produces Plain Old Java Objects (POJOs) for the microservice's business logic. These objects are optimized for performance, enhancing developer productivity by managing object serialization, transport and persistence.
The following is the user code for a basic Rumi microservice. This illustrative microservice processes a HelloRequest message by updating a counter in its database and returns a HelloReply message with the updated counter value and an arbitrary string.
The Rumi runtime drives all user code within a Rumi microservice. User-written code falls into the following two categories:
Lifecycle methods
Message handlers
Lifecycle Methods
The Rumi runtime oversees the lifecycle of a Rumi application by executing user-defined methods to handle various lifecycle functions:
Accessor Methods
The Rumi runtime invokes such methods to gather user-specific data necessary for its operation. The getStateFactory() method above is invoked to obtain the factory used to instantiate the root object of the microservice's store. This ensures Rumi can instantiation the microservice store at the appropriate point in microservice lifecycle
Injection Methods
The Rumi runtime invokes such methods to supply the user code with handles to Rumi runtime objects for use by the user code in its operation. The setMessageSender() method above us an example of such a method. Rumi invokes this method, if implemented, to supply the user code with a an instance of the AepMessageSender object that the user code uses to send outbound messages.
Notification Methods
The Rumi runtime invokes such methods to notify the user of lifecycle and alert related events. The init() and the onMessagingPrestart() methods are examples of such methods. The init()method is invoked to notify the user code that the main microservice class - HelloService - was just loaded while onMessagingPrestart() is invoked to notify the user code that the Rumi runtime is about to connect to the underlying configured messaging bus.
Message Handlers
Business logic within Rumi microservices is driven by messages. This means all business logic is executed through message handlers, which are methods marked with the @EventHandler annotation and recognized by their method signature. The onMessage() method above is an example of a message handler.
Message Handlers are single-threaded and should generally be non-blocking. They consume messages, perform business logic, query and/or update state and send outbound messages. The Rumi runtime ensures that message receipt, state updates, and outbound sends are atomic, reliable, and loss-free, even in case of failures.
See Authoring User Code for more information on writing event and message handlers.
@AppHAPolicy(value = StateReplication)
public class Main {
private AepMessageSender sender;
/**
* Invoked by Rumi runtime at startup to initialize the microservice
*/
@AppInitializer
public void init() {
System.out.println("Initialized");
}
/**
* Invoked by the Rumi microservice runtime to inject a message sender for use by the user code
*/
@AppInjectionPoint
public void setMessageSender(AepMessageSender messageSender) {
this.messageSender = messageSender;
}
/**
* Invoked by Rumi microservice runtime just before it connects to the underlying messaging provider
*/
@EventHandler
public void onMessagingPrestart(final AepMessagingPrestartEvent event) {
System.out.println("About to start messaging");
}
/**
* Invoked by Rumi microservice runtime to fetch the root of the microservice store
*/
@AppStateFactoryAccessor
public IAepApplicationStateFactory getStateFactory() {
return new IAepApplicationStateFactory() {
@Override
final public Store createState(MessageView view) {
return Store.create();
}
};
}
/**
* Called by the Rumi microservice runtime on receipt of a HelloRequest message.
*/
@EventHandler
public void onMessage(HelloRequest helloRequest, Store store) {
// update store
store.setCounter(store.getCounter() + 1);
// send hello reply
HelloReply helloReply = HelloReply.create();
helloReply.setText("Hi There");
helloReply.setCounter(store.getCounter());
messageSender.sendMessage("hello-replies", helloReply);
}
}