Architecture – Cyclic dependencies in microservices

architectural-patternsArchitecturedependency analysismicroservices

Just wanted to know if cyclic dependency is something that one should avoid in microservice design.

For example, let's say we have a simple web store that sells fruit.

It could have:

  • Account Service – where all information about accounts is stored
  • Order Service – where all the information about orders is stored
  • Fruit Stock Service – a simple listing of fruits, their availability
    is stock and prices.

Let's say that we want to forbid our users buying more than 10 bananas total. And put the info about banana availability on the screen.

So which is the better way to do it:

  1. Have Fruit Stock Service make a request to a Order Service to get all previous user orders and return it with the bananas price and stock info. In this case we have a cyclic dependency because Order Service needs to know about fruit and Fruit Stock Service needs to know about orders

  2. Have a separate request to Order Service (something like 'Can user 111 buy item 222'). In this case we have to make 2 separate request to know if we should show bananas to this user or not.

Best Answer

Let's first get rid of a misconception

The microservice architecture "structures the application as a set of loosely coupled, collaborating services":

  • Collaborating mean that microservices may need to work together to achieve a higher objective. They may therefore need to know (or find out) how to work with other microservices, and perhaps even to rely on them.
  • Loosely coupled means that each microservice is well encapsulated and can be replaced by another microservice offering the same "contract", the same external interface.

The goal of this architecture is allow you to compose many simpler microservices in order to offer complex services that can be scaled. Achieving this goal does not mean that microservices are independent, but that they are that are independently deployable. And that's a big difference

Your question in theory

If a microservice A depends on a microservice B you must be able to deploy a new version of A without touching B. So the services are dependent but they can be independently deployed. As a real-life example, look at the relation between authorisation and product microservices in the Netflix stack.

If there is a cycle however, one should analyse if the service decomposition did went to far:

  • If microservice A depends on B, but at the same time B depends on A, it starts to look very much like a strong coupling. This means that something did not work as it should. Verify if both functionality should not be packaged as a single microservice.
  • If a microservice A depends on a microservice B, which depends on microservice C which depends on microservice A, it's less obvious, but the service decomposition should be challenged for the same reason.

Note that the dependency can very well be indirect (e.g. via a message queue)

Your question in practice

Let's look at the rule: "forbid our users buying more than 10 bananas total":

  • the rule is a condition for accepting the order, so it needs to be checked as part of Order Service
  • to verify the rule, you need to find all past orders of the customer (in a given time frame?) and aggregate the quantity by product. This would therefore typically be implemented as part of Order Service
  • so for your question, there is no need for questions: everything would be performed as part of one microservice.

But you could imagine less trivial scenarios:

  • Order Service could need to look for stock availability to inform the user of out-of-stock items during the ordering process. Either you'd make sure that all stock events are forwarded to order service. Or you would make Order Service addressing a request to Stock Service.
  • In B2B, it would not be uncommon that Order Service needs to do a credit check for accepting an order, since the customer would pay after having received the goods. Credit management usually combines information from lot of sources (e.g. external credit rating agencies, outstanding orders, outstanding invoices, payment history, etc...). It would be a good candidate for a microservice. But credit management requires to get invoices from accounting, which might receive them from order management. So a circular dependency is something that can happen.
Related Topic