-
Notifications
You must be signed in to change notification settings - Fork 543
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
Query-frontend: use activity tracker for requests #3561
Conversation
The CHANGELOG has just been cut to prepare for the next Mimir release. Please rebase |
e35460a
to
2d1c630
Compare
Rebased and force-pushed ✅ |
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.
Thanks. I'd suggest to simplify the PR: ignore errors when generating activity description, and use real activity tracker for testing.
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.
Thanks for adding this!
When setting the default "time" param, if the form was already parsed (by some previous middleware) we didn't propagate that change into r.Form. In order to solve that, we're now replacing the r.Body with a readCloseSeeker, that can be seeked to the beginning again and again. This change isn't so important on itself, but it's needed to make #3561 work properly, as there we're going to parse the request form at the beginning of the request in order to generate the activity. Additionally, though not important, note that we were never checking the POST request body, in case the "time" was specified there, and that's where Prometheus API client is sending it, so we were always setting the default "time" param on the Query, and it worked just because if it was also sent in the body, that would take precedence when parsing the form (but it was a waste of resources since we had to parse and render the query string again all the times). Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
bad5876
to
2a6678c
Compare
@pracucci @pstibrany rebased, force-pushed. Ready for 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.
I've left some comments, but this should work. Thank you!
pkg/frontend/transport/handler.go
Outdated
params := copyValues(r.Form) | ||
|
||
// Seek the body back to the beginning, so it can be read again if it's used to forward the request through a roundtripper. | ||
if _, err := seeker.Seek(0, io.SeekStart); err != nil { |
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.
If we read the body into bytes buffer (which we do, but then wrap it), we wouldn't need to call Seek
here, but instead set body to r.Body = io.NopCloser(bytes.NewReader(buf))
.
"seeker" abstraction seems unnecessary here.
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.
Seeker allows next user of r.Body
to just seek it back instead of having to read it again to a new buffer in order to replace it.
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 don't think there is another user of r.Body doing that (except http -> httpgrpc conversion, which reads body into new buffer again).
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 would also be very strange if there was code checking if r.Body
implements Seeker. That's very unusual interface for HTTP request body to implement, given that it's typically streamed over network.
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 don't see the point in hiding functionality that saves memory allocation. io.NopCloser
just hides the Seek
method, and what I'm doing here is not hiding it. I can only see positive effects of that.
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 once again we make things little bit more complicated and generic than they need to be. But my intention is not to block the PR on this, feel free to merge it as-is.
// Parse the form, as it's needed to build the activity for the activity-tracker. | ||
if err := r.ParseForm(); err != nil { | ||
writeError(w, apierror.New(apierror.TypeBadData, err.Error())) | ||
return | ||
} |
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.
If activity tracker is disabled, this is unnecessary. Although it may be better to keep it for consistent handling of all requests.
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.
Given the stats are enabled by default, and tracker too, I'd just keep it here. If it's unnecessary, it's not a big deal.
pkg/frontend/transport/handler.go
Outdated
// Store the r.Form contents copy, as middlewares may modify it (like setting the default values). | ||
params := copyValues(r.Form) | ||
|
||
// Seek the body back to the beginning, so it can be read again if it's used to forward the request through a roundtripper. |
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.
The fact that we reset the Body, but keep r.Form
non-nil is a red flag. While it is probably OK, it leaves Request
in the state which handler or middlewares may not expect, and is different than before this PR.
As an alternative, we could make a copy of request (with the same buffered body), and only parse form in the copy, and use that for activity tracking and logging.
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 can't see why it's a red flag.
it leaves Request in the state which handler or middlewares may not expect
Neither handler or middlewares should expect undocumented states. There's no docs saying that a non-nil r.Form
indicates an empty body.
I don't think that we need to parse twice just because someone takes a wrong assumption somewhere else.
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.
There's no docs saying that a non-nil r.Form indicates an empty body.
non-nil r.Form
implies that ParseForm
was called (based on Form
field documentation), and ParseForm
is documented to read the body for POST, PUT or PATCH request with Content-Type: application/x-www-form-urlencoded
.
Since our middlewares don't currently parse the form, we wouldn't parse it twice.
Anyway, well behaved middlewares (ie. all in Mimir) are not making any such assumptions, so we don't need to worry about it anymore.
1039d35
to
052f56a
Compare
Query-frontend uses the activity-tracker for the PromQL engine, but that is just for the sharded queries execution. Query-frontend does much more than that, and we should also track that. This adds every HTTP request received by the Handler to the activity tracker. Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
Appliedi Peter's comments. Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
052f56a
to
32f2b00
Compare
Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
* Query-frontend: use activity tracker for requests Query-frontend uses the activity-tracker for the PromQL engine, but that is just for the sharded queries execution. Query-frontend does much more than that, and we should also track that. This adds every HTTP request received by the Handler to the activity tracker. Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com> * Update CHANGELOG.md Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com> * Store a copy of params Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com> * Restore the original request state Appliedi Peter's comments. Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com> * Fix a comment Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com> Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
What this PR does
Query-frontend uses the activity-tracker for the PromQL engine, but that is just for the sharded queries execution. Query-frontend does much more than that, and we should also track that.
This adds every HTTP request received by the Handler to the activity tracker.
Which issue(s) this PR fixes or relates to
Fixes (none)
Checklist
CHANGELOG.md
updated - the order of entries should be[CHANGE]
,[FEATURE]
,[ENHANCEMENT]
,[BUGFIX]