-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#849 #1496 Extend the route key format used for load balancing making it unique #1944
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Steven,
Your proposal for the key format is
UpstreamHttpMethod,+|UpstreamHost|UpstreamPathTemplate|ServiceNamespace|ServiceName
OR
UpstreamHttpMethod,+|UpstreamHost|UpstreamPathTemplate|Host:Port,+
Maybe to include Type of Load Balancer for the second variant instead of Host:Port
?
Because UpstreamPathTemplate
cannot vary, so it is unique, seems Host:Port
is redundant... and type of load balancer cannot vary too...
@ggnaegi Welcome to code review! |
I thought about it, what I want to do is make the route key format the same for all types of configs, because the differences in the format are causing me confusion. Proposed format, which now includes the load balancer options instead of downstream host/port:
However, for this to work correctly, empty parts must be kept, because removing empty parts will again lead to ambiguous route keys. For example:
It's not clear if this means |
I had to make a few more changes based on new information and test results. The route key is now calculated uniformly for all kinds of load balancers (except sticky session load balancing which uses static keys.) The format is now:
I had to keep the I added For undefined route properties, the undefined parts are replaced by default values: -GET,POST,PUT|/api/product||10.0.0.1:8080||||
+GET,POST,PUT|/api/product|no-host|10.0.0.1:8080|no-svc-ns|no-svc-name|no-lb-type|no-lb-key The default values don't serve any technical purpose, but it came up in the review that empty parts look like a mistake when it's actually not. |
Let me know if you have any more suggestions. Otherwise, I'm happy with the current state of this branch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, thanks
@raman-m do you have time this week to review? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raman-m do you have time this week to review?
@sliekens Yes, I do..now... 😉
We have some unit tests. Nice!
It would be good if we add 1 acceptance test too.
I guess we have some acceptance tests already: so we could update old ones.
But better to add new test which covers UpstreamHost
user scenario and other props of the route.
@raman-m I added a test with two services, each with a different I have verified that it fails as expected on the develop branch, before my changes: (Ocelot reuses the route of the first service, load balancing is not working correctly) When I run the test on this branch, it passes. Additional info:
As before, let me know if you have any more questions or suggestions, otherwise, I'm happy with these changes as is. |
e3c394a
to
896e0ad
Compare
Questionz
|
I did all of my testing with the |
I've converted the acceptance fact to theory: Also, in debug session I noticed that key is build always without reading from the cache...
I hope that is correct. |
Based on docs in case of Upstream Host in a route
and
and
Question: How do you setup the header in acceptance tests? |
It's important to understand that the You can copy the acceptance test to the
That is intended. The cache should not be used when calling two different services exactly once. I could add a step to call the same service more than once, which then uses the cache instead of making another call to Consul. However, I felt that it is already sufficiently covered by other existing tests. |
Yep, it is added implicitly, when you do this: _ocelotClient.GetAsync("http://us-shop/products"); It is translated to a request like: GET /products HTTP/1.1
Host: us-shop |
Thanks for the explanation! It's much clearer now.
But you don't call |
Intended not to load balancer? )) But this is the test about load balancing 🤣
Clear!
Yes, please make the test complete.
Other acceptance tests even use counter approach to check times of calling! private void GivenProductServiceOneIsRunning(string url, int statusCode)
private void GivenProductServiceTwoIsRunning(string url, int statusCode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found major issue with usage of GivenThereIsAServiceRunningOn
which is based on the one private variable. But the status of both downstream services must use different private variables!
this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceUrlUS, "/", 200, responseBodyUS)) | ||
.And(x => x.GivenThereIsAServiceRunningOn(downstreamServiceUrlEU, "/", 200, responseBodyEU)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is wrong!
Pay attention to other tests which use 2 services.
Valid setup should be:
this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceUrlUS, "/", 200, responseBodyUS)) | |
.And(x => x.GivenThereIsAServiceRunningOn(downstreamServiceUrlEU, "/", 200, responseBodyEU)) | |
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceUrlUS, "/", 200, responseBodyUS)) | |
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceUrlEU, "/", 200, responseBodyEU)) |
In current GivenThereIsAServiceRunningOn
helper you use shared private variable _downstreamPath
deciding on status OK. But I guess it is wrong!
You have to decide on url + path, but not only on path.
Optional
Also, _serviceHandler
should be different! So, you have to start two instances of webservers of downstream services.
The setup is: 2 different product services, with different names, and 2 corresponding Consul entries. Requests to Ocelot with There must be no load balancing between The bug in develop branch is that PS: I originally said that calls to Consul are cached, but that is false. Only responses from |
@raman-m with the explanation above, do you still feel the test is incomplete? While it is true that the bug is in the /edit: I added a Consul request counter and repetitive Ocelot calls, to verify load balancing and service discovery are working correctly. I hope these changes are in line with your expectations, otherwise don't hesitate to comment. |
I love this explanation! ❤️ 😉 Thanks!
Correct!
Correct! Default implicit type of poller is |
After your adding last 4 commits the test is complete now! It looks great! 😍
Now the acceptance test is awesome thing! It shows most complete user scenario which can be described for UpstreamHost case. Finally, I'd say: we have Done development! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ready for delivery! ✅
- Code review ✔️
- Team approvals ✔️
- Unit tests ✔️
- Acceptance test(s) ✔️
Fixes #849 #1496
UpstreamHost
property isn't working #849Proposed Changes
RouteKeyCreator
aware ofUpstreamHost
routingRouteKeyCreator
aware of ServiceDiscovery withServiceName
andServiceNamespace
Multiple routes with identical
UpstreamMethod
andUpstreamPath
, but differentUpstreamHost
andServiceName
orDownstreamHostAndPort
will now be load-balanced correctly.