-
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 context to ReporterV2 #11451
Add context to ReporterV2 #11451
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.
@andrewkroh Would be great to get your opinion on this change.
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 like the change. I think I originally didn't go for context.Context because it was a pretty new API at the time.
With this change it seems that there is no longer a need to have a separate Reporter
and PushReporter
. So I think we can deprecate the PushReporter
interfaces. Existing push reporters can migrate to use the context's Done() method.
Another thought I had (but no investigation) is that Metricbeat metricset's have a configurable timeout
option IIRC. I don't think this option is used much (or implemented properly in most metricsets), but when it is used we could pass a context that has been wrapped WithTimeout
.
@@ -212,15 +219,15 @@ func (r *CapturingReporterV2) GetErrors() []error { | |||
// ReportingFetchV2 runs the given reporting metricset and returns all of the | |||
// events and errors that occur during that period. | |||
func ReportingFetchV2(metricSet mb.ReportingMetricSetV2) ([]mb.Event, []error) { |
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'm afraid that I believe that we shouldn't add context at all 😅 There are two main rules when implementing context:
context.Context
must be propagated from the initial call sofunc ReportingFetchV2(metricSet mb.ReportingMetricSetV2) ([]mb.Event, []error)
must befunc ReportingFetchV2(ctx context.Context, metricSet mb.ReportingMetricSetV2) ([]mb.Event, []error)
. Propagation is key when using context.context.Context
must not be stored anyhow. It's a continuation of the previous, if you follow the rule of propagation, you won't store it at all.
Finally, I don't see a real benefit of using context here. I mean that it looks like it's a "we can use Context here, as many other approaches" instead of a "it's a clear use case of Context". Also, I feel that we are replacing a piece with a explicit implementation which was already working. Explicit code is idiomatic in Go :)
A not so old post about this: https://dave.cheney.net/2017/08/20/context-isnt-for-cancellation
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'm afraid that I believe that we shouldn't add context at all 😅 There are two main rules when implementing context:
*context.Context
must be propagated from the initial call sofunc ReportingFetchV2(metricSet mb.ReportingMetricSetV2) ([]mb.Event, []error)
must befunc ReportingFetchV2(ctx context.Context, metricSet mb.ReportingMetricSetV2) ([]mb.Event, []error)
. Propagation is key when using context.* `context.Context` must not be stored anyhow. It's a continuation of the previous, if you follow the rule of propagation, you won't store it at all.
In general I agree with that, but I'd like to avoid adding yet another interface (two of them if adding the one returning an error, plus its testing related code). We'd have to evaluate if it worths to add more interfaces for this.
Also this is a pattern also used in the standard library, for example HTTP handlers receive a Request that has a Context()
.
The context is only being stored where it is created, in the wrapper. We can continue with future refactorizations to replace Start(done <-chan struct{})
with Start(ctx context.Context)
so we have a context that can be propagated from there.
Finally, I don't see a real benefit of using context here. I mean that it looks like it's a "we can use Context here, as many other approaches" instead of a "it's a clear use case of Context". Also, I feel that we are replacing a piece with a explicit implementation which was already working. Explicit code is idiomatic in Go :)
Well, most of our modules make requests to other services and many client libraries accept contexts.
The main benefit is that we can start using a context that makes sense in the current module lifecycle instead of using Background()
, TODO()
or avoiding APIs with contexts.
It is not using it "as many other approaches", it is using it as the approach that afaik is more widely used in the standard and third party libraries (even if we can discuss if it is the best approach).
A not so old post about this: https://dave.cheney.net/2017/08/20/context-isnt-for-cancellation
Nice read, but I think that start using something like tomb
would require a huge effort in the case of Metricbeat, while getting a context from a done channel we already have is quite straightforward. Also many libraries we use expect contexts, if we use other things we still need to convert them.
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.
When the first version of Beats was written, Context did not exist yet and we started with the done
channel. Would we build it again I would assume Context would play quite a role in it. Long term I think more and more parts should be switched over to context but we need to go baby steps here (like in this PR). At least that is my thinking.
Thanks @andrewkroh and @sayden for your comments. I totally agree about deprecating the Regarding the timeout option, afaik it is only used in modules using the HTTP helper. With this context we could make it a more general setting, and we could also refactor the helpers to do requests with contexts. |
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.
@jsoriano Could you rebase this on master? Quite a few of the failing tests should have been fixed by now.
CHANGELOG-developer.next.asciidoc
Outdated
@@ -40,3 +40,4 @@ The list below covers the major changes between 7.0.0-beta1 and master only. | |||
- Added support for using PYTHON_EXE to control what Python interpreter is used | |||
by `make` and `mage`. Example: `export PYTHON_EXE=python2.7`. {pull}11212[11212] | |||
- Prometheus helper for metricbeat contains now `Namespace` field for `prometheus.MetricsMappings` {pull}11424[11424] | |||
- ReporterV2 implements context.Context |
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.
Can you add the PR number?
+1 to using context, we have been bitten by wild requests in the past. From what I understand, you went with passing context as part of reporter (instead of arg to
In general I'm good with the compromise, although having it explicit as a parameter would avoid some user mistakes, as you need to know reporter offers a |
I don't have an strong preference, the new one is more explicit. What do others think? @sayden @andrewkroh |
I left some comments 🙂 |
I will continue with the more explicit approach in #11981, thanks all for the feedback. |
Add a
context.Context
based on thedone
channel metricsetwrapper receives. This way all
Fetch()
methods will have a contextthat can be used in their clients and requests.
As example two metricsets are migrated to use the new context, one using
ReporterV2
and another one usingPushReporterV2
.