-
Notifications
You must be signed in to change notification settings - Fork 275
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
persisted queries have client names #6198
Conversation
✅ Docs Preview ReadyConfiguration{
"repoOverrides": {
"apollographql/router@main": {
"remote": {
"owner": "apollographql",
"repo": "router",
"branch": "glasser/pq-client-name"
}
}
}
}
9 pages published. Build will be available for 30 days. |
This comment has been minimized.
This comment has been minimized.
CI performance tests
|
{ | ||
if let Some(persisted_query_body) = manifest_poller.get_operation_body( | ||
persisted_query_id, | ||
request.context.get(CLIENT_NAME).unwrap_or_default(), |
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.
This probably implies that the new feature only works if Apollo telemetry is enabled. This is probably a reasonable constraint for an initial release, but we should at least document it.
.cloned() | ||
{ | ||
Some(body) | ||
} else if client_name.is_some() { |
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.
Do we need this else if? It looks like we would be returning the null operation for the a request for an operation with a client_name. If client_name
is Some and nothing exists in state.persisted_query_manifest
for it, None
feels like the right 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.
What this is saying is — if we don't have an operation that is specifically designated for this client name, try one that was published without a client name. (If we didn't have this, all PQs would suddenly stop working for any clients that send a client name as soon as you upgraded to this version.)
The reason it's a conditional at all instead of just an "else try client_name: None
" is because if client_name
is None, it would be making the same exact call twice, which seems wasteful.
I should add comments to this function though!
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.
Ooohhhh riiight! that totally makes sense! comment will definitely help, but logic is definitely good! thanks :)
e20b1d2
to
7348223
Compare
hashmap! {"accounts".to_string() => 1} | ||
); | ||
|
||
// Successfully run a persisted query with client name that has its own operation, |
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 not sure how to add an integration test that tests the "client name read from the header named by telemetry.apollo.client_name_header
because I'm not sure if there's an easy way to enable the part of the telemetry code that reads the header without setting up a full reporting agent situation. (Maybe it would be OK for the PQ code to directly read this config field from the configuration instead? I had trouble getting that to work though.)
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 are other integration tests that actually spin up a router, see the apollo-router/tests
directory. This enables a full testing of a feature including telemetry.
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.
That is the directory I'm in?
That said, this becomes trivial if I'm able to make the change mentioned above where the telemetry config is respected even when telemetry isn't enabled.
@@ -172,7 +172,7 @@ pub(crate) mod tracing; | |||
pub(crate) mod utils; | |||
|
|||
// Tracing consts | |||
const CLIENT_NAME: &str = "apollo_telemetry::client_name"; | |||
pub(crate) const CLIENT_NAME: &str = "apollo_telemetry::client_name"; |
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.
This PR involves various pub and pub(crate) changes; this one is to make the actual logic work, and others are to make the integration tests work. I don't know if that's appropriate, just that it makes it build.
I think this is ready for an initial review. It still needs docs and a changeset entry, but it is code complete and has tests. I'd appreciate advice on how to write one particular test as mentioned in my comment. |
request | ||
.supergraph_request | ||
.headers() | ||
.get(client_name_header_default_str()) |
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.
This won't be right if the user has configured a custom client header name.
Telemetry puts the client name into the context. So why do we need to check for a header at all 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.
It seemed reasonable to have the feature not be completely broken if telemetry isn't enabled (which, eg, was the case in the integration tests). Eg if you're running your router locally with your client that's built to sent PQs. That said I feel like I'd be happier if I could get the implementation to be "honor telemetry.apollo.client_name_header
even if APOLLO_KEY isn't set" but I couldn't quite figure out a comfortable way to get access to the plugin configuration from outside of 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 suppose another potential approach would be to refactor the telemetry plugin somehow so that it puts the client name in the context even if the actual reporting mechanism isn't enabled via API key.)
hashmap! {"accounts".to_string() => 1} | ||
); | ||
|
||
// Successfully run a persisted query with client name that has its own operation, |
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 are other integration tests that actually spin up a router, see the apollo-router/tests
directory. This enables a full testing of a feature including telemetry.
(oops, I'd been testing with |
3941062
to
80f2c83
Compare
assert_eq!(actual.data, None); | ||
assert_eq!(registry.totals(), hashmap! {"accounts".to_string() => 1}); | ||
|
||
// We didn't break normal GETs. |
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.
This particular sub-test got lost because the samples files don't let me specify GET requests with checked responses.
@BrynCooke OK, this still lacks docs/changelog, but it's using a simpler form of testing that makes it more clear that the telemetry plugin is always loaded, so I was able to remove the |
784cc06
to
f985c5e
Compare
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.
Looks great with the new json based tests.
I still think unit testable parts should be unit tested though.
f985c5e
to
03a70d1
Compare
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.
@BrynCooke OK, docs and changeset and unit tests done! I think this is ready for final consideration. Hoping it gets into v1.59.0! I'll coordinate the Rover and GraphOS-server-side changes.
@@ -138,6 +138,20 @@ To enable safelisting, you _must_ turn off [automatic persisted queries](/router | |||
|
|||
</Note> | |||
|
|||
### Customization via request 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.
Note that there may be a second entry in this section soon depending on how ROUTER-890 is implemented.
921fe00
to
bf7ba2c
Compare
bf7ba2c
to
8b459b7
Compare
!docs preview main |
This depends on unreleased functionality of GraphOS.
0797d3e
to
2bbe77c
Compare
!docs preview main |
2bbe77c
to
54e79ca
Compare
!docs preview main |
(This depends on functionality of GraphOS that is not currently enabled for all users, as well as an unreleased version of Rover.)
The persisted query manifest fetched from Uplink can now contain a
clientName
field in each operation. Two operations with the sameid
but differentclientName
are considered to be distinct operations (and may have distinct bodies).Router resolves the client name by taking the first of these which exists:
apollo_persisted_queries::client_name
context key (which may be set by arouter_service
plugin)telemetry.apollo.client_name_header
(which defaults toapollographql-client-name
)If a client name can be resolved for a request, Router first tries to find a persisted query with the specified ID and the resolved client name.
If there is no operation with that ID and client name, or if a client name cannot be resolved, Router tries to find a persisted query with the specified ID and no client name specified. (This means that existing PQ lists that do not contain client names will continue to work.)
This PR also improves the internal "samples" integration test suite:
The existing PQ integration test is moved into the "samples" suite.