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.
-
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?Bart van Ingen Schenau– Bart van Ingen Schenau2019年06月19日 12:48:45 +00:00Commented Jun 19, 2019 at 12:48
-
yes for the first scenario I mentioned, but this may not always be the case with other complex scenariosrohanagarwal– rohanagarwal2019年06月19日 12:57:13 +00:00Commented Jun 19, 2019 at 12:57
-
1When 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– JimmyJames2019年06月19日 14:25:29 +00:00Commented 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?rohanagarwal– rohanagarwal2019年06月20日 06:06:18 +00:00Commented Jun 20, 2019 at 6:06
-
1If you thinking about versioning microservices - you doing something wrong.Fabio– Fabio2019年06月21日 07:27:16 +00:00Commented Jun 21, 2019 at 7:27
1 Answer 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/
Explore related questions
See similar questions with these tags.