Inter-process communication for Microservices

Inter communication between different domain specifics is overwhelming and attracting so much attention in modern day microservices deployment. Microservices architecture is all about desegregating the applications into fine-grained services. To implement any business use case, theses services have to interact with each other as well as with any other existing systems such as web APIs and databases, over the network. So, building inter-service/process communication is absolutely critical for microservices.

Generally microservices-based architecture, dividing very complex structure into independently developed and deployed services, which result in forming a mesh with many communication links, therefore, often the division is not as obvious as it would seem, and not every component which encapsulates logic related to a table becomes a separated microservice.

Considering the decoupling aspects, when architecting how your services will communicate, it always require to consider various issues that may popped when the inter services communication mechanism , thus, besides that, how services interact, how to specify the API for each service, how to evolve the APIs, and how to handle partial failure are common questions to be asked. The common inter communication patterns 2 types:

  • Synchronous
  • Asynchronous

Synchronous / REST HTTP

Nothing being much changed in this context, it is preliminary a request-response style communication. HTTP protocol has been the standard for years, and that is no different for microservices world too. It is a synchronous, stateless protocol. In synchronous communication, the client sends a request and waits for a response from the service. Interestingly, using that protocol, the client can communicate asynchronously with a server, which means that a thread is not blocked , and the response will reach a callback eventually.

Asynchronous , Event/ Message‑Based Communication

The Main idea of the asynchronous events/ messaging should be not blocking a request process thread while waiting for a response. Most probably we know such communications can be handled with messaging brokers. The, message consumers can consume messages from a message broker/event bus, and producers can produce messages to an event bus, messaging patterns will be primarily based on either pub-sub or queue based communication.

The message producer usually does not wait for a response. It just waits for acknowledgment that the message has been received by the broker. The most popular protocol for this type of communication is AMQP (Advanced Message QueuingProtocol). An asynchronous messaging system may be implemented in a one-to-one(queue) or one-to-many (topic) mode.

Building inter-process communication with Ballerina

Let’s try to illustrate the and communication styles with Trip management design. If you look at the diagram given below,

In Microservices architecture, The services use a combination of notifications, request/response, and publish/subscribe. For example, the passenger’s smartphone sends a notification to the Trip Management service to request a pickup. The Trip Management service verifies that the passenger’s account is active by using request/response to invoke the Passenger Service. The Trip Management service then creates the trip and uses publish/subscribe to notify other services including the Dispatcher, which locates an available driver.

So, lets have look at communication styles used by the Trip manager component. As stated in the diagram, the Trip manager component suppose to communicate with the passenger management service to get caller information. Once the caller is verified by the system, the system should be able to notify to the client seamlessly while working background to complete the trip request and matching appropriate driver information, then, later notify to the client mobile device with the driver information asynchronously, so in higher level this looks very simple. Anyway, let’s look at how to snipperst of Trip manager component

// Initialize a JMS connection with the provider
// ‘providerUrl’ and ‘initialContextFactory’ vary based on the JMS provider you use
// ‘Apache ActiveMQ’ has been used as the message broker in this example
jms:Connection jmsConnection = new({…});
// Initialize a JMS session on top of the created connection
jms:Session jmsSession = new(jmsConnection,….. });

// Client endpoint to communicate with passenger management service
endpoint http:Client passengerMgtEP {
// Service endpoint
endpoint http:Listener listener {port:9090};
// Trip manager service, which is managing trip requests received from the client
@http:ServiceConfig {basePath:”/trip-manager”}
service<http:Service> TripManagement bind listener {
// Resource that allows users to place an order for a pickup
@http:ResourceConfig { methods: [“POST”], consumes: [“application/json”],
produces: [“application/json”], path : “/pickup” }
pickup(endpoint caller, http:Request request)
// synchronously call passenger service validate client // upon validating client prepare pick reference per dispatcher request // asynchronously communicate with dispatcher to coordinate with the driver // response client related to the trip allocation status status }

Simulating Synchronous invocation

Ballerina provides native network aware constructs that provide the abstraction for interaction with endpoints via disparate network protocols. Ballerina offers support by default for most of the standard network communication protocols. For an instance lets have look at how easily you could derine client interface to communicate external services

Defining passenger-management endpoint reference

endpoint http:Client passengerMgtEPurl:”http://localhost:9091/passenger-management"

Within the resource call passenger management endpoint to obtain client information for business validation

http:Response passengerResponse= check passengerMgtEP -> post(“/claims”,passengerManagerReq);

You will notice that, the response object reference (passengerResponse) upon service dispatch. This communication style basically adhere to the request-response communication style.

Initializing event driven dispatcher, the sample demonstrate the scenario with JMS integration

// Initialize a queue sender using the created session
endpoint jms:QueueSender jmsTripDispatchOrder { session:jmsSession, queueName:”trip-dispatcher”};

Refer below code which simulating jms one way communication between the dispatcher service. Here basically we just put message to the broker queue where, the dispatcher would waiting for the messages in trip-dispatcher queue

// Dispatch to the dispatcher service
// Create a JMS message
jms:Message queueMessage = check jmsSession.createTextMessage(passengerResponseJSON.toString());
// Send the message to the JMS queue
log:printInfo(“Hand over to the trip dispatcher to coordinate driver and passenger:”);
_ = jmsTripDispatchOrder -> send(queueMessage);

Simulating Asynchronous invocation

On the other hand once the passenger finalized then, the communication to the dispatcher is . Here the trip management service will dispatch pickup information to the dispatcher, then, the dispatcher would retrieving the pickup information via consumer channel asynchronusly followed by the dispatcher will coordinate with the other subsystems to complete the pickup. Please refer blow code snippet demonstrate the asynchronous consumer channel implementation with Ballerina syntax.

jms:Session jmsSession = new(conn, {acknowledgementMode: "AUTO_ACKNOWLEDGE" });endpoint jms:QueueReceiver jmsConsumer {session:jmsSession, queueName:”trip-dispatcher”};service<jms:Consumer> TripDispatcher bind jmsConsumer 
onMessage(endpoint consumer, jms:Message message)
// implementing logic to communicate subsystems based on pickup event received from the trip-manager }}

If you refer the code snippet the jms:Connection is used to initialize a JMS connection with the provider details. initialContextFactory and providerUrl configuration change based on the JMS provider you use.

jms:Session is used to initialize a session with the required connection properties.

Resource onMessage will be triggered whenever the queue specified as the destination gets populated.

Try it Out!

Please refer microservice intercommunication guide demonstrating scenario described in this blog.

You can download the Ballerina distributions, try samples, and read the documentation in the Learn page. You can also visit the Quick Tour to get started. We encourage you to report issues, improvements, and suggestions at the Ballerina Github Repository. Also please do refer Philosophy to understand other communication styles.

Architect/Associate Director WSO2