1

I have a few questions regarding the versioning in the microservices architecture:

Let's say there are three services - S1, S2, S3

S1 calls S2 and S3 to generate a response R1. Service S2 generates response R2 and service S3 generates response R3.

Supported versions:
S1 - 1.0.0, 1.0.1
S2 - 1.0.0, 1.0.1
S3 - 1.0.0

In the version 1.0.0 for Service S1, the response R1 contains two fields - F1, F2. F1 is derived from response R2 and F2 is derived from response R3.

In the version 1.0.1 for the service S1, the response R1 contains 3 fields - F1, F2 and F3.
And, in the version 1.0.1 of the service S2, there is a new field added which is used to derive the F3 field for the response R1.

To summarize:

S1 -> R1 (F1, F2) - version 1.0.0  
S1 -> R1 (F1, F2, F3) - version 1.0.1  
S2 -> R2  
S3 -> R3

How should I be writing the code in the service S1 such that it makes call to service S2 version 1.0.1 when the version specified by the consumer of the service S1 species the version as 1.0.1 and it makes the call to service S2 version 1.0.0 when the version specified by the consumer of the service S1 species the version as 1.0.0?

Another Scenario:

 S1 -> R1 (F1, F2) - version 1.0.0 and 1.0.1  
 S2 -> R2 (F3, F4) - version 1.0.0   
 S2 -> R2 (F3, F5) - version 1.0.1  
 S3 -> R3 (F6) - version 1.0.0
 F1 is derived from R2 and F2 is derived from R3.  

I am looking for some clean way of managing this which is extensible as well as maintainable. Majority of the solutions talk about the versioning strategies like versions in the URLs or in the headers, but not about the design patterns governing the internal implementations.

Let's assume, that service S1 has a controller layer and then a service layer. The calls to other services are made in the service layer.

I am representing a case of backward compatible changes/contract for service S1. For incompatible changes, I can create a version specific implementation in the service layer.

9
  • If S1 calls version 1.0.1 of S2, would it then still be able to create a version 1.0.0 R1 by ignoring the information that isn't needed? Commented Jun 19, 2019 at 12:48
  • yes for the first scenario I mentioned, but this may not always be the case with other complex scenarios Commented Jun 19, 2019 at 12:57
  • 1
    When you have a lot of complex relationships you create between services, you are really building a distributed monolith. The big idea that makes microservices work is independence. Here's an article that discusses this at a high level.
    – JimmyJames
    Commented Jun 19, 2019 at 14:25
  • But I am talking about something where there are changes in the response of one MS, how is it not going to affect the other dependent MS? Or are you saying, each and every MS should be completely independent? Commented Jun 20, 2019 at 6:06
  • 1
    If you thinking about versioning microservices - you doing something wrong.
    – Fabio
    Commented Jun 21, 2019 at 7:27

1 Answer 1

1

One way to approach Microservices Versioning is to add automated checks that can effectively guarantee that all your service versions, their responses, and respective fields are compatible in all possible dependency chains.

I'm thinking about dependency chains, for example as:
Chain1 S1_1.0.0 <-> (S2_1.0.0, S3_1.0.0);
Chain2 S1_1.0.1 <-> (S2_1.0.1, S3_1.0.0);

One way to approach this kind of automated checks is Pact testing.

In my understanding Pact testing was developed to test systems with a Microservices Architecture, and during development, it supports Versioning scenarios (which I believe, is your use case).

This type of testing uses concepts that can help you structure code to accomplish this:
- Consumer
- Interaction
- Pact Provider
- Expected request
- Minimal expected response

More detailed information can be found at https://docs.pact.io/

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.