-
Notifications
You must be signed in to change notification settings - Fork 10.3k
[Question] Shared integration events #724
Comments
The goal for microservices is that they be self-contained, and not have to be updated based on changes in other projects or services. Thus, some duplication is desirable in this case if it means that changes in one microservice do not need to impact the others. |
@ AlexanderSysoev - Great question! 👍 THE POINT: Share between microservices only what you would also share between different/independent applications. 👍 However, In the specific case of Integration Events I should also say that some developers prefer to share the types/libraries between microservices. In this case we chose to be more independent between microservices, so not to couple multiple microservices to a single "event's library". |
I know we've talked about this more than once, but I'm hanging on @CESARDELATORRE's last paragraph. I think that there IS A REAL AND IMPORTANT dependency between microservices that share integration events, because those teams at some point reached an agreement to settle on that information exchange spec (it's a contract after all), so I think it's actually good to have that dependency expressed in code somehow, and a shared library looks like a good option. Am I way off? |
My point is that for microservices integration you should take a similar approach than for application integration. Both microservices and application development must be independent/autonomous. But, as always, this decision must depend on the application's context. |
Fair enough! |
In the case each microservice has its own copy of an integration event:
So, as mentioned by @mvelosop there was, at some point, an agreement that created a contract. That leads me to the following conclusion (feel free to add to it, by agreeing or disagreeing):
So whatever the technique used, the messages (events) still need to be in the same format (or at least be similar) in all microservices (publishers and subscribers), so the dependency is there no matter what (hidden or not). Personally, for most scenarios, I think I'd go for discoverability and code sharing (DRY) over "falsy decoupling" and copy/paste. Finally, as stated by @CESARDELATORRE : "But, as always, this decision must depend on the application's context." |
@AlexanderSysoev Consider each microservice would be developed by different language and different platform for example python or java. |
Closing this discussion now (it was a nice - and recurring - one), will reopen if needed. |
Interesting topic indeed. |
Hi @dgrandemange, thanks for the link, it looks quite interesting to take a detailed look at 👍 BTW, you might want to take a look at the new centralized logging feature we have now, with a nice example on integration events handling. Hope this helps. |
Hi But I also imagine the situation when we have 3 microservices for example A, B, C. Correct me if I'm wrong. Thanks |
@alexanderbikk I believe that contract belongs to concrete microservice, it is not a "proxy" between them. According to this microservices B and C exposes their own contracts. If microservice A need to interact with B and C you should reference B and C contracts in A. When interaction between A and B changes, you change contract B and update microservices A and B only. |
@AlexanderSysoev ok, I understand. So, I should have separate library with contracts for each service(if I choose approach with shared libraries). Am I right? |
@alexanderbikk you are right |
Hi @alexanderbikk, @AlexanderSysoev, I also thought that sharing a library on integration events was something good, and even argued with @CESARDELATORRE about that, as you might have seen above. But that was seven months ago! However, while implementing the logging system, I realized that even though integration events have the same name in different microservices, they have different properties in each one (at least some of them), to handle only the properties each microservice really cares about. Then I realized that, for example, one team might find it useful to implement a calculated property that adds value in a microservice, but would be confusing somewhere else, so that property should not "leak" out to others. So, nowadays I agree 100% with @CESARDELATORRE on this subject. Hint, the guy knows a bit 😉. |
Hi @mvelosop. I also thought about case that you described when we have different properties in contracts in different microservices. It allows more flexibility during deployment. So I deploy only microservice where the contract was changed and don't touch the other services that also using this contract. Thank you, guys |
Hi @CESARDELATORRE , @mvelosop. After some time thinking about shared integration events I completely understand your reasons for not sharing "business" assemblies, and sharing only cross-cutting concerns (building blocks). However, what should we do if we have multiple microservices following DDD (like Ordering in eShopOnContainers)? Where should we place Entity, ValueObject, IAggregateRoot, IRepository and similar classes? Should we share these classes among multiple microservices or every microservice should have its own implementation? These classes don't deal with some business concerns, but still I'm not sure about the right place for them. |
Hi @nemanjarogic, I think, at least as of today 😉, that it's mainly a matter of team size. Or perhaps more about team dynamics, if it's easy for your team to agree on code to share, then do it and consider this as you would any other "general-use" package like MediatR or whatever. I you start feeling like you're loosing too much time arguing, then don't share the code now. This is not "bad" either, it can help you find a better overall solution, based on real usage. BTW, my general approach to this now is, I don't share anything out from the start. When actual usage patterns emerge, then I begin to consider refactoring the common parts out to a library, but the code has to "show its worth in actual battles" to achieve such a status. I just lost the count of one-use libraries I created 😅 Hope this helps. |
I think everybody agrees that publishing / consuming events in a microservice creates an integration contract. I also believe everybody thinks making these contracts / dependencies explicit is a good thing, while also keeping your microservice technically decoupled from other microservices. So, my take here is to treat these contracts as any other contract. Wherever I have a contract (owned or consumed) I need to have some VERSIONING mechanism in place, and some EXPLICIT versioning POLICY for producers and consumers. For example, defining a "standard" way for an event to include some contract version information (like a "version field" or something like that), defining that a breaking change makes mandatory changing the major version of the contract, and so on. How the consumer service would react to a missing field, or an additional field it don't recognizes. So, in the case of integration events, if your application needs to live in an environment where integration contracts might change (or change a lot) maybe is valuable to implement some extra protections for those cases. Complexity has a cost.... and a good tradeoff is always valuable. Perfect is the enemy of Good.... Agv |
In your application integration events has duplicate in several microservices. For example UserCheckoutAcceptedIntegrationEvent is located in Basket.API and Ordering.API. Would it be the best to share contracts between microservices (place integration events in separate assembly)?
The text was updated successfully, but these errors were encountered: