2

Something that annoys me when reading about decoupling microservices is that the problem is often stated, with either poorly explained, bad, or no solutions provided, which seems to especially be the case with synchronous communication.

Take this basic example of a customer and orders microservice:

The customer service holds the customer's details, like their credit card. Orders needs details from the customer service, like their credit card, to create an order. Therefore, the communication between the client and services would probably need to look as follows for a new order request:

How could you avoid synchronous communication in a common situation like this? An asynchronous "fire and forget" pattern seems to be infeasible since we need a customer's information to create an order, but maybe I'm incorrect.

2
  • 2
    The Client asks the CustomerService first and only when it has the CreditCard and makes a call to the OrderService. Basically, the client orchestrates the steps to reach the last one. To decouple services, you must embrace the idea that services are "agnostic" to the source of the data they get as input. They expect the input, they don't go for it. They are only responsible and accountable for the outputs.
    – Laiv
    Commented Oct 18, 2022 at 15:30
  • @Laiv Thanks, and so sorry to reply to this a year late! I'm just curious about the security implication of doing that - isn't it unsafe to pass intermediary data to the client when it could be avoided (especially in the case of sensitive info like credit cards)? Commented Oct 4, 2023 at 21:00

4 Answers 4

9

If the "order service" needs credit card information to do its job, why isn't that information there?

Services are not database tables. They provide specific business-related functions to their users. Not data to other services.

Now, admittedly, this is easier said than done, but this is the basis on which synchronous (request-response) communication can be avoided. Basically the above design is flawed. Services shouldn't be cut this way.

3
  • I completely understand what you mean, but my idea here was that another service besides orders might need that credit card as well from the customer service (admittedly credit card isn't the best example). What might a situation like that look like? Thanks Commented Oct 17, 2022 at 22:24
  • 1
    One way to solve that is that when a user registers their credit card in the customer service, that service broadcasts an event. Other services can subscribe to certain events, so they can store the data in their own database. The other services will not have to do synchronous queries to the origin when they need data, because they have their own copy.
    – Rik D
    Commented Oct 17, 2022 at 22:36
  • 5
    @TheCornInspector Sorry but there are no general answers - it depends upon the specific requirement and the reason why it wouldn't be feasible to simply merge all of those services into a single service. i.e. if you have 3 different services that all need credit card details, then what prevents you merging them together? Remember microservices are merely a deployment solution; more importantly they add a steep cost in complexity so best avoided if reasonably possible; otherwise it's a case of focusing on whatever specific requirements need separate deployments and work from there. Commented Oct 18, 2022 at 7:16
3

Orders needs details from the customer service, like their credit card, to create an order.

Are you sure? Isn't it better for PCI-DSS to not pass the credit card around? If you were using an external payment service like Stripe, you wouldn't see it at all. And it would be a synchronous process of passing the order to Stripe at the right point in the flow.

And that's the key to microservice design. If you're ever designing both sides of a microservice, you're doing it wrong, and you should just design one service that contains both parts. You should imagine that every microservice is provided by a separate company.

Microservices are more an organizational tool than a deployment one. They allow different parts of the software to be worked on by completely independent teams that communicate only through published APIs.

(In response to edit: yes, I do mean to refer to different parts of the software. The originator of microservices is usually considered to be the Bezos API memo. https://nordicapis.com/the-bezos-api-mandate-amazons-manifesto-for-externalization/ ; it makes sense to think of the Amazon website as "a piece of software" even though it's comprised of a large number of components and (micro)services maintained by a large number of teams.)

2

First of all, Robert's answer applies. The complete service separation seems a mess, fix it.

Then, even in asynchronous operation, you can use a message to request the credit card details, and an answer message which provides these details. The rder service just stops with its process until the answer message arrives.

This is called "request reply pattern" in the book "Enterprise integration patterns" (and frankly, you should not even think the word "microservice", if you have not read that book.)

As you naturally have monitoring, restarting and scheduling in place (no microservices without), even when the customer service is down at request time, it will only take a second until your monitoring system has restarted the service, so that for the customer, there is just a slight delay.

3
  • 1
    "use a message to request the credit card details, and an answer message which provides these details." -- this is very confusing. I really don't see the benefit of waiting for the results of a query. Credit card information should either be supplied by the end user (and hence already exists) or the lookup for that information should be a GET request that returns quickly. Submitting the order (and thereby changing the state of the system) makes sense as a message. And then it makes sense for the client to wait for an "order accepted" message. Commented Oct 18, 2022 at 16:48
  • 1
    @GregBurghardt "or the lookup for that information should be a GET request that returns quickly": no. Then you introduce direct and tight coupling and create a big ball of mud. If you really want to use REST to communicate between microservices,, you need to care about service discovery, service selection, failover, and probably circuit breaking. This is much more effort than simply communicating via the well defined and tried request-reply pattern. But all in all, synchronous communication should be avoided as much as possible, e.g. by having the data in the right place from the start.
    – mtj
    Commented Oct 19, 2022 at 4:01
  • 1
    Direct requests are not a bad design in micro services. It is only bad when every interaction is a direct HTTP call. You need to choose the appropriate medium for each use case. In my opinion, message passing for simple data retrieval is overkill. Service discovery, failover, and circuit breaking are all concerns with message-based services as well. To be honest, if you send a message to a specific topic or queue, wait for a response, and that listener isn't running, you are still coupled. If you cannot proceed without a response, the coupling still exists. Commented Oct 19, 2022 at 12:22
1

The short answer is you can't avoid synchronous communication here. Even if you did an async HTTP call to the customer service, the order service needs to wait for the data before it can proceed with its work.

If you want to avoid having to call the customer service every time, you can have the order service replicate the data it needs, and use some event driven mechanism to keep it up to date.

Depending on the data and the rest of your system, you could do this a couple of different ways. You could have the customer service emit a simple event when a change is made, like "Hey something about customer X changed", and all services that care can call in to find out what the change was so they can update their own records if they need to.

Alternatively you could have the customer service actually include the details in the event, like "Hey customer X changed their billing address from ____ to ____". This is a pattern Martin Fowler referred to as Event Carried State Transfer. It means the dependant services don't ever need to directly call the customer service.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.