DEV Community

Raphael De Lio
Raphael De Lio

Posted on

The 3 Mechanisms of Interaction between Microservices: Command, Query, and Event

Twitter | LinkedIn | YouTube | Instagram

In my previous story, I discussed the six principles of Microservices Architecture that I learned through Urs Peter's course on Event-Driven Architecture. Today, I'd like to share another concept I learned in his course: the three types of mechanisms of interaction between Microservices: Command, Query, and Event.

First of all, let's take a step back and remember one of the key principles of Microservices architecture that I shared in my previous story: "Async Message Passing." I wrote:

In asynchronous message passing, a microservice sends a message to another service without waiting for an immediate response. The sending service continues its operation and can handle the response later in time. This often involves an event-driven architecture where services react to events and communicate changes through messages.

We already know that Microservices should communicate through asynchronous messages, often enabled by an event-driven architecture. What we haven't discussed yet is that those messages may fall under two categories: Command and Event. Let's break them down:

Event

Events are about notifying other parts of the system that something has happened, like facts that something has happened in the past. They are more about information dissemination than direct action. The producer of an event has no expectations that the event will result in any action. Hence, the producer doesn’t expect any response in return.

A booking service from an aviation system may notify other systems that a booking has been made. Let's see what it could look like:

{
  "eventType": "BookingCreated",
  "timestamp": "2024-01-29T12:00:00Z",
  "bookingDetails": {
    "bookingId": "BK12345",
    "customerId": "C12345",
    "flightDetails": {
      "flightNumber": "FL123",
      "departureAirport": "JFK",
      "arrivalAirport": "LAX",
      "departureTime": "2024-02-15T08:00:00Z",
      "arrivalTime": "2024-02-15T11:00:00Z"
    },
    "passengerDetails": [
      {
        "passengerId": "P12345",
        "firstName": "John",
        "lastName": "Doe",
        "dateOfBirth": "1990-05-15",
        "passportNumber": "P12345678"
      },
      {
        "passengerId": "P12346",
        "firstName": "Jane",
        "lastName": "Doe",
        "dateOfBirth": "1992-08-20",
        "passportNumber": "P87654321"
      }
    ],
    "contactDetails": {
      "email": "johndoe@example.com",
      "phone": "+1234567890"
    },
    "paymentDetails": {
      "paymentStatus": "Confirmed",
      "amountPaid": 800.00,
      "currency": "USD",
      "paymentMethod": "CreditCard",
      "transactionId": "TX123456789"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Every time a new event is published, other systems that are interested in new bookings may listen, collect this information, and decide how to process it. A Loyalty Points service could check if the customer has a loyalty account and calculate points based on the flight distance, for example. A Flight Management service could use this event to update the seat availability for this specific flight.

Command

Commands, in contrast to events, are about instructing a system to perform a specific action or change its state. While events are purely informational, indicating that something has occurred, commands are directive and expect the receiving system to execute a certain task or operation.

Following our previous example, after our Flight Management service has updated the seat availability of the flight, it could issue an AdjustFlightPricing command to the Revenue Management System, instructing it to reassess and potentially update the flight's pricing based on the new seat availability and current demand trends. This is what this command could look like:

{
  "commandType": "AdjustFlightPricing",
  "flightDetails": {
    "flightNumber": "FL123",
    "departureAirport": "JFK",
    "arrivalAirport": "LAX",
    "departureDate": "2024-02-15",
    "departureTime": "08:00:00"
  },
  "pricingDetails": {
    "currentOccupancyRate": 75, // Percentage of seats booked
    "averageTicketPrice": 300.00,
    "seatsRemaining": 50,
    "demandTrend": "Increasing",
    "historicalData": {
      "samePeriodLastYearPrice": 280.00,
      "samePeriodLastYearOccupancy": 65
    }
  },
  "action": "ReassessPricing"
}
Enter fullscreen mode Exit fullscreen mode

When the Revenue Management System receives this payload, it can use sophisticated pricing algorithms and historical data to decide whether to adjust the flight’s pricing. Depending on the requirements, it could also issue events to notify other systems that the flight's pricing has been adjusted.

Well, I said there were three mechanisms and only mentioned two so far. What about Query, you may ask? Well, queries imply by nature that you want data right away, so you are willing to wait. Therefore, they’re usually done through synchronous communication. Let's take a closer look at it.

Query

Queries are requests for information or data. Unlike events or commands, queries are free of side effects; they leave the state of the system unchanged. Usually, queries are synchronous operations that can be implemented over protocols like HTTP or gRPC.

For instance, in the Loyalty Points service, queries let us access information like customer loyalty points, transaction history, and rewards without modifying any system data. These operations are vital for showing up-to-date information on websites or mobile apps, and helping customers and service staff in decision-making and account management.

For example, to check a customer’s current loyalty points, we might use an endpoint like: GET /api/loyalty/customers/{customerId}/points. A mobile app could use this to show a user's points balance. Similarly, to view different loyalty tiers, we could use: GET /api/loyalty/tiers.

This allows real-time data retrieval for websites or mobile apps, eliminating the delays associated with waiting for asynchronous message processing.

Event-Driven MicroServices Training

The “Event-Driven Microservices Training” by Urs Course is open to all interested in enhancing their knowledge of Event-Driven Architecture, and I highly recommend it.

This two-day, in-person course is conducted in the Netherlands. For upcoming dates and pricing details, visit Event-Driven Microservices Training.

Contribute

Writing takes time and effort. I love writing and sharing knowledge, but I also have bills to pay. If you like my work, please, consider donating through Buy Me a Coffee: https://www.buymeacoffee.com/RaphaelDeLio

Or by sending me BitCoin: 1HjG7pmghg3Z8RATH4aiUWr156BGafJ6Zw

Follow Me on Social Media

Stay connected and dive deeper into the world of Software Architecture with me! Follow my journey across all major social platforms for exclusive content, tips, and discussions.

Twitter | LinkedIn | YouTube | Instagram

Top comments (0)