-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Add new interfaces for ReporterV2 with context #11981
Add new interfaces for ReporterV2 with context #11981
Conversation
f884447
to
b1ceef9
Compare
I preferred #11451 as it does not add one more interface and context is hidden in the background. But that is just personal preference. |
f4c61cd
to
ba7c1a6
Compare
In principle I'd also prefer to avoid adding a new interface. But one of the reasons I don't like of having many interfaces is that every time we change an interface in a module, even if the change is small there we also have to change the tests. It can be also tricky for developers and contributors to know what method to use depending on the interface they are implementing. #11131 or #11998 can help on reducing the pain points of having many interfaces. |
I like the idea to reduce the paint points around many interfaces but we should still strive to support as few as possible. |
If I can give my humble 2 cents 🙂 Generally, I see we don't embrace much of the composition nature in Go. For example the type ReportingMetricSetV2 interface {
MetricSet
Fetch(r ReporterV2)
} When I think it should look more like this: type ReportingMetricSetV2 interface {
MetricSet
FetcherV2
}
type FetcherV2 interface {
Fetch(r ReporterV2)
} So when adding error handling we can have this: type ReportingMetricSetV2Error interface {
MetricSet
FetcherV2
FetcherWithError
}
type FetcherWithError interface {
FetchWithError(r ReporterV2) error
} And with context, for example: type FetcherWithContext interface {
FetchWithCtx(ctx context.Context, r ReporterV2) error
}
type NiceReporterV2 interface {
MetricSet
FetcherWithError
FetcherWithContext
FetcherV2
} And because they don't all have the same method name BUT 😄 Actually this methodology won't scale well here if we need to keep adding "options" so I think that a better approach would look similar to this: // Don't try to copy-paste, I did this directly on github xD
type ReporterV3 interface {
Event(ctx context.Context, event Event, opts ...Option) error // Event reports a single successful event.
Error(ctx context.Context, err error, opts ...Option) error
}
type FetcherV3 interface {
FetchWithCtx(ctx context.Context, r ReporterV3) error
}
type MetricsetFetcherV2 interface {
Metricset
FetcherV3
}
type Option interface {
GetOption() interface{}
}
func NewErrorHandlingOption() Option {
return &ErrorHandlingOption{}
}
type ErrorHandlingOption struct {}
func (c *ErrorHandlingOption) GetOption() interface{} {
return func(err error){
fmt.Println(err)
}
} Sorry, I couldn't spent time really looking at Instead of keep adding interfaces that requires migration of all modules or will have an inconsistent interface use, I think we need a more general approach to this: context and error must always be used or, at least, experience has taught me that 100% of the times you'll regret to not return errors and 90% of not using context when doing network IO. |
@sayden I am not sure of following, lots of mixed ideas here.... I totally embrace composition 🙂 but I don't think it benefits so much here. For example, what would implement these Regarding this The options arguments can be a good thing, and could be added in a backwards compatible way, but I am not sure when we would use them. I'd leave this for the first use case we find. Regarding the error example, I'd leave this discussion for other threads (it was also slightly discussed here).
This is exactly the idea of the interfaces we have now, metricsets only need to implement one of the fetcher methods, and the framework takes care of everything else. The recent addition of the error interface also goes in this direction, so metricsets don't have to care on how errors are reported. In the only point when they have to care about something is in the tests, where they have to use specific methods depending on the interfaces they have implemented, #11131 or #11998 would fix this part by making all metricsets to be tested the same way, no matter what interface they implement.
Migrating all modules was never in my mind, this is why I originally thought on adding this as a method of the reporter. I'd only migrate the modules that are currently using contexts, and maybe others that would benefit of it, but with very low priority. I don't see such an inconsistency on having a couple of interfaces to choose. I agree that returning errors and using contexts are good things, but I wouldn't think on forcing all modules to use contexts, several of them would require deeper changes to take advantage of them. |
@sayden as summary to unblock this a little bit 🙂 what would you prefer?
|
I feel like my order of preference would be
Again, that was my 2 cents only, you are good to go with whatever option you consider. All in all you are the one who has spend more time with this now 😉 |
Ok, I will continue with this option, thanks for the feedback. |
I am going to resurrect this, actually it would be ready for review after deciding that we go with this option. |
After elastic#11981 docker client watching event uses the context provided by the metricset wrapper. This produces a race condition on error reporting: the errors channel will receive a context cancelled error when the context is done, so both paths can be chosen by the select. If the errors one is chosen, an error will be reported and a reconnect will be attempted, that will fail. Alternativelly we could have created another context and cancel it after the reporter is done, in a similar fashion to what was done before elastic#11981, but then we would be breaking the chain of derived contexts.
After #11981 docker client watching event uses the context provided by the metricset wrapper. This produces a race condition on error reporting: the errors channel will receive a context cancelled error when the context is done, so both paths can be chosen by the select. If the errors one is chosen, an error will be reported and a reconnect will be attempted, that will fail. Alternativelly we could have created another context and cancel it after the reporter is done, in a similar fashion to what was done before #11981, but then we would be breaking the chain of derived contexts.
…tic#12743) After elastic#11981 docker client watching event uses the context provided by the metricset wrapper. This produces a race condition on error reporting: the errors channel will receive a context cancelled error when the context is done, so both paths can be chosen by the select. If the errors one is chosen, an error will be reported and a reconnect will be attempted, that will fail. Alternativelly we could have created another context and cancel it after the reporter is done, in a similar fashion to what was done before elastic#11981, but then we would be breaking the chain of derived contexts. (cherry picked from commit d36878a)
…) (#12849) After #11981 docker client watching event uses the context provided by the metricset wrapper. This produces a race condition on error reporting: the errors channel will receive a context cancelled error when the context is done, so both paths can be chosen by the select. If the errors one is chosen, an error will be reported and a reconnect will be attempted, that will fail. Alternativelly we could have created another context and cancel it after the reporter is done, in a similar fashion to what was done before #11981, but then we would be breaking the chain of derived contexts. (cherry picked from commit d36878a)
…tic#12743) (elastic#12849) After elastic#11981 docker client watching event uses the context provided by the metricset wrapper. This produces a race condition on error reporting: the errors channel will receive a context cancelled error when the context is done, so both paths can be chosen by the select. If the errors one is chosen, an error will be reported and a reconnect will be attempted, that will fail. Alternativelly we could have created another context and cancel it after the reporter is done, in a similar fashion to what was done before elastic#11981, but then we would be breaking the chain of derived contexts. (cherry picked from commit fcedb16)
Alternative implementation of #11451, to provide a context to fetchers
in a more explicit way by receiving a context as parameter of
Fetch
or
Run
.For that two new interfaces are added with their testing methods.
As example two metricsets are migrated to use the new context, one using
ReporterV2
and another one usingPushReporterV2
.