Skip to content

Commit

Permalink
Progressive override: fix query planner cache warmup (#6108)
Browse files Browse the repository at this point in the history
The query planner needs various metadata along with the query to influence planning, and due to historical reasons that data was passed through the request context, not the planner request. The progressive override labels list was communicated like that, but missed the case of query plan cache warmup, where upon schema or configuration updates, the router takes the list of most used queries from the query planner's in memory cache, and plans them again before activating the new schema or configuration. Due to the mistake, the labels were not transmitted during warmup, which resulted in queries correctly using the overridden fields, but after an update, would revert to non overridden fields, and could not recover (unless the plan was evicted from the cache).

Co-authored-by: Jesse Rosenberger <[email protected]>
  • Loading branch information
Geal and abernix authored Oct 30, 2024
1 parent b75689c commit d31da83
Show file tree
Hide file tree
Showing 16 changed files with 764 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changesets/fix_geal_progressive_override_test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Progressive override: fix query planner cache warmup ([PR #6108](https://github.com/apollographql/router/pull/6108))

This fixes an issue in progressive override where the override labels would not be transmitted to the query planner during cache warmup, resulting in queries correctly using the overridden fields at first, but after an update, would revert to non overridden fields, and could not recover.

By [@Geal](https://github.com/Geal) in https://github.com/apollographql/router/pull/6108
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
version: 2.1

# Cache key bump: 1

# These "CircleCI Orbs" are reusable bits of configuration that can be shared
# across projects. See https://circleci.com/orbs/ for more information.
orbs:
Expand Down
5 changes: 5 additions & 0 deletions apollo-router/src/query_planner/caching_query_planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,11 @@ where
lock.insert(caching_key.metadata)
});

let _ = context.insert(
LABELS_TO_OVERRIDE_KEY,
caching_key.plan_options.override_conditions.clone(),
);

let request = QueryPlannerRequest {
query,
operation_name,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Progressive override

This tests subgraph field migration: https://www.apollographql.com/docs/federation/entities/migrate-fields/
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
include_subgraph_errors:
all: true

telemetry:
exporters:
logging:
stdout:
format: text

experimental_query_planner_mode: legacy

plugins:
experimental.expose_query_plan: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include_subgraph_errors:
all: true

telemetry:
exporters:
logging:
stdout:
format: text

experimental_query_planner_mode: legacy

rhai:
scripts: "tests/samples/enterprise/progressive-override/basic/rhai"
main: "main.rhai"

plugins:
experimental.expose_query_plan: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
{
"enterprise": true,
"actions": [
{
"type": "Start",
"schema_path": "./supergraph.graphql",
"configuration_path": "./configuration.yaml",
"subgraphs": {
"Subgraph1": {
"requests": [
{
"request": {
"body": {
"query": "query progressive1__Subgraph1__0{percent100{__typename id}}",
"operationName": "progressive1__Subgraph1__0"
}
},
"response": {
"body": {
"data": {
"percent100": {
"__typename": "T",
"id": "1"
}
}
}
}
}
]
},
"Subgraph2": {
"requests": [
{
"request": {
"body": {
"query": "query progressive1__Subgraph2__1($representations:[_Any!]!){_entities(representations:$representations){...on T{foo}}}",
"operationName": "progressive1__Subgraph2__1",
"variables": {
"representations": [
{
"__typename": "T",
"id": "1"
}
]
}
}
},
"response": {
"body": {
"data": {
"_entities": [
{
"foo": 1
}
]
}
}
}
},
{
"request": {
"body": {
"query": "query progressive2__Subgraph2__0{percent0{foo}}",
"operationName": "progressive2__Subgraph2__0"
}
},
"response": {
"body": {
"data": {
"percent0": {
"foo": 2
}
}
}
}
}
]
}
}
},
{
"type": "Request",
"request": {
"query": "query progressive1 { percent100 { foo } }"
},
"headers": {
"apollo-expose-query-plan": "false"
},
"expected_response": {
"data": {
"percent100": {
"foo": 1
}
}
}
},
{
"type": "Request",
"request": {
"query": "query progressive2 { percent0 { foo } }"
},
"expected_response": {
"data": {
"percent0": {
"foo": 2
}
}
}
},
{
"type": "ReloadConfiguration",
"configuration_path": "./configuration2.yaml"
},
{
"type": "ReloadSubgraphs",
"subgraphs": {
"Subgraph1": {
"requests": [
{
"request": {
"body": {
"query": "query progressive3__Subgraph1__0{percent100{__typename id}}",
"operationName": "progressive3__Subgraph1__0"
}
},
"response": {
"body": {
"data": {
"percent100": {
"__typename": "T",
"id": "1"
}
}
}
}
},
{
"request": {
"body": {
"query": "query progressive4__Subgraph1__0{percent100{bar}}",
"operationName": "progressive4__Subgraph1__0"
}
},
"response": {
"body": {
"data": {
"percent100": {
"bar": 2
}
}
}
}
}
]
},
"Subgraph2": {
"requests": [
{
"request": {
"body": {
"query": "query progressive3__Subgraph2__1($representations:[_Any!]!){_entities(representations:$representations){...on T{bar}}}",
"operationName": "progressive3__Subgraph2__1",
"variables": {
"representations": [
{
"__typename": "T",
"id": "1"
}
]
}
}
},
"response": {
"body": {
"data": {
"_entities": [
{
"bar": 1
}
]
}
}
}
}
]
}
}
},
{
"type": "Request",
"request": {
"query": "query progressive3 { percent100 { bar } }"
},
"headers": {
"apollo-expose-query-plan": "false"
},
"expected_response": {
"data": {
"percent100": {
"bar": 1
}
}
}
},
{
"type": "Request",
"request": {
"query": "query progressive4 { percent100 { bar } }"
},
"headers": {
"apollo-expose-query-plan": "false",
"x-override": "true"
},
"expected_response": {
"data": {
"percent100": {
"bar": 2
}
}
}
},
{
"type": "Stop"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
fn supergraph_service(service) {
const request_callback = Fn("process_request");
service.map_request(request_callback);
}

// Add a timestamp to context which we'll use in the response.
fn process_request(request) {
request.context["request_start"] = Router.APOLLO_START.elapsed;
let labels = request.context["apollo_override::unresolved_labels"];
print(`unresolved: ${labels}`);

let override = request.context["apollo_override::labels_to_override"];
print(`override: ${override}`);


if "x-override" in request.headers {
if request.headers["x-override"] == "true" {
request.context["apollo_override::labels_to_override"] += "bar";
}
}
}

Loading

0 comments on commit d31da83

Please sign in to comment.