-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
[SUPERCEDED] package sd #235
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
Conversation
- Refactor the main Subscriber loop - Register uses AgentServiceRegistration - Improve tests, including integration test
|
Oh — I obviously haven't deleted package loadbalancer from this PR yet :) Updated examples to come soon. |
sd/lb/round_robin.go
Outdated
| var old uint64 | ||
| for { | ||
| old = atomic.LoadUint64(&rr.c) | ||
| if atomic.CompareAndSwapUint64(&rr.c, old, old+1) { |
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.
Maybe I'm misunderstanding this, but instead of doing a load+cas in a loop couldn't this just use an atomic add? For example:
old := atomic.AddUint64(&rr.c, 1) -1 // subtract 1 to get the previous value
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.
Yes, I think you are right :) In my defense, this code was left over from a long time ago and I didn't really rethink it. Thank you for the spot!
|
Is |
|
I'm pretty happy with |
|
Just thinking out loud. Maybe How about |
|
Yes, Registrar may make more sense. Something like this? // Registrar registers instance information to a service discovery system when
// an instance becomes alive and healthy, and deregisters that information when
// the service becomes unhealthy or goes away.
//
// Registrar implementations exist for various service discovery systems. Note
// that identifying instance information (e.g. host:port) must be given via the
// concrete constructor; this interface merely signals lifecycle changes.
type Registrar interface {
Register()
Deregister()
} |
|
I just added a PR to the |
|
Is there a particular reason the cache package is made internal? This would be annoying for people wanting to use the cache for writing their own subscribers to proprietary discovery systems. |
|
I did not anticipate cache being used by third-party Subscriber implementations. I made it internal primarily for cleanliness, I'm happy to move it out if you think there might be a desire for it. |
|
It would help me out. I have a subscriber implementation based on curator-go :) |
| errc <- err | ||
| return | ||
| } | ||
| if len(s.tags) > 1 { |
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.
It probably should be noted why this filtering is done in the client, how using prepared queries is desired yet not feasible currently.
Did you dig deeper into the issue of prepared queries not supporting blocking calls? Otherwise I'm happy to explore in that direction.
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.
Yes, good point, I will add some documentation.
re: lack of support, the Consul issue for querying on multiple tags was closed when prepared queries were introduced, but the execute endpoint "does not support blocking queries" so
¯\_(ツ)_/¯
|
Porting the examples reveals some unwanted friction between factories, services, and endpoints. I need to iterate on the interaction between those components. Thanks to @basvanbeek for highlighting some of these problems early. |
|
The Service abstraction created a number of problems.
Consequently, I'm not comfortable moving forward with the Service abstraction. But, everything else in the PR seems OK. So I will rework this PR. For my own edification, the work to be done is
|
This is a big change.
Package loadbalancer has been deleted, and is replaced by package sd. What was previously loadbalancer.Publisher becomes sd.Subscriber, which I believe better reflects its purpose. That is, the sd/consul.Subscriber is subscribing to updates from Consul.
Additionally, we introduce a new type, sd.Registrar, responsible for advertising the lifecycle of the Go kit service into the corresponding service discovery system. That is, sd/consul.Registrar registers updates to Consul.
This is optional, as many users prefer to or must have their orchestration system manage entries in their service discovery system. But for those users who do self-registration, this will be useful. Addresses #167.
Astute readers will note another big change: the Subscriber no longer emits raw endpoint.Endpoints, but a new type, service.Service. A Service is a logical collection of named endpoints intended to represent a complete microservice.
A Service is probably implemented as a simple
map[string]endpoint.Endpoint. Method names have no particular schema and are totally up to users. The factory methods given to an sd.Subscriber must now convert an instance string (host:port) into a Service rather than an Endpoint. This makes much more sense: previously, users would need near-identical factories (and loadbalancer.Publishers) for every individual endpoint they wanted to interact with, which was very tedious.With those important distinctions in mind, I've mostly just ported the existing loadbalancer code to sd. A few additional changes:
There are a few additional things I want to do, which I will probably leave to subsequent PRs:
Comments, pointers to things I may have forgotten, and bitter complaints that I am changing core Go kit semantics — all are greatly appreciated :)