diff --git a/.changesets/feat_geal_evaluate_plan_count.md b/.changesets/feat_geal_evaluate_plan_count.md new file mode 100644 index 0000000000..663ce74239 --- /dev/null +++ b/.changesets/feat_geal_evaluate_plan_count.md @@ -0,0 +1,6 @@ +### Add a histogram metric tracking evaluated query plans ([PR #5875](https://github.com/apollographql/router/pull/5875)) + +The `supergraph.query_planning.experimental_plans_limit` option can be used to limit the number of query plans evaluated for a query, to reduce the time spent planning. When reaching that limit, the planner would still return a valid query plan, but maybe the most optimized one. +This adds the `apollo.router.query_planning.plan.evaluated_plans` histogram metric to track the number of evaluated query plans, giving more context to configure this option. + +By [@Geal](https://github.com/Geal) in https://github.com/apollographql/router/pull/5875 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e5781a7a0d..135142ad6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5630,9 +5630,9 @@ dependencies = [ [[package]] name = "router-bridge" -version = "0.6.0+v2.9.0" +version = "0.6.1+v2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef4910ade6753863c8437a76e88e236ab91688dcfe739d73417ae7848f3b92" +checksum = "b3be2d3ebbcbceb19dc813f5cee507295c673bb4e3f7a7cd532c8c27c95f92fc" dependencies = [ "anyhow", "async-channel 1.9.0", diff --git a/apollo-router/Cargo.toml b/apollo-router/Cargo.toml index c5925efc12..11d470ec24 100644 --- a/apollo-router/Cargo.toml +++ b/apollo-router/Cargo.toml @@ -197,7 +197,7 @@ regex = "1.10.5" reqwest.workspace = true # note: this dependency should _always_ be pinned, prefix the version with an `=` -router-bridge = "=0.6.0+v2.9.0" +router-bridge = "=0.6.1+v2.9.0" rust-embed = { version = "8.4.0", features = ["include-exclude"] } rustls = "0.21.12" diff --git a/apollo-router/src/query_planner/bridge_query_planner.rs b/apollo-router/src/query_planner/bridge_query_planner.rs index 6f0ab174cf..43024cdea6 100644 --- a/apollo-router/src/query_planner/bridge_query_planner.rs +++ b/apollo-router/src/query_planner/bridge_query_planner.rs @@ -304,6 +304,7 @@ impl PlannerMode { if let Some(node) = &mut root_node { init_query_plan_root_node(node)?; } + Ok(PlanSuccess { usage_reporting, data: QueryPlanResult { @@ -311,6 +312,11 @@ impl PlannerMode { query_plan: QueryPlan { node: root_node.map(Arc::new), }, + evaluated_plan_count: plan + .statistics + .evaluated_plan_count + .clone() + .into_inner() as u64, }, }) } @@ -532,6 +538,7 @@ impl BridgeQueryPlanner { QueryPlanResult { query_plan: QueryPlan { node: Some(node) }, formatted_query_plan, + evaluated_plan_count, }, mut usage_reporting, } => { @@ -549,6 +556,12 @@ impl BridgeQueryPlanner { doc.clone() }; + u64_histogram!( + "apollo.router.query_planning.plan.evaluated_plans", + "Number of query plans evaluated for a query before choosing the best one", + evaluated_plan_count + ); + let generated_usage_reporting = generate_usage_reporting( &signature_doc.executable, &doc.executable, @@ -844,6 +857,7 @@ impl BridgeQueryPlanner { pub struct QueryPlanResult { pub(super) formatted_query_plan: Option>, pub(super) query_plan: QueryPlan, + pub(super) evaluated_plan_count: u64, } impl QueryPlanResult { @@ -1595,4 +1609,23 @@ mod tests { "init.is_success" = false ); } + + #[test(tokio::test)] + async fn test_evaluated_plans_histogram() { + async { + let _ = plan( + EXAMPLE_SCHEMA, + include_str!("testdata/query.graphql"), + include_str!("testdata/query.graphql"), + None, + PlanOptions::default(), + ) + .await + .unwrap(); + + assert_histogram_exists!("apollo.router.query_planning.plan.evaluated_plans", u64); + } + .with_metrics() + .await; + } } diff --git a/docs/source/configuration/telemetry/instrumentation/standard-instruments.mdx b/docs/source/configuration/telemetry/instrumentation/standard-instruments.mdx index d29cbf1fca..828a764f24 100644 --- a/docs/source/configuration/telemetry/instrumentation/standard-instruments.mdx +++ b/docs/source/configuration/telemetry/instrumentation/standard-instruments.mdx @@ -66,6 +66,7 @@ The coprocessor operations metric has the following attributes: - `apollo.router.query_planning.plan.duration` - Histogram of plan durations isolated to query planning time only. - `apollo.router.query_planning.total.duration` - Histogram of plan durations including queue time. - `apollo.router.query_planning.queued` - A gauge of the number of queued plans requests. +- `apollo.router.query_planning.plan.evaluated_plans` - Histogram of the number of evaluated query plans. - `apollo.router.v8.heap.used` - heap memory used by V8, in bytes. - `apollo.router.v8.heap.total` - total heap allocated by V8, in bytes. diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index f01ccac721..dfbb4c9725 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -20,7 +20,7 @@ reqwest = { workspace = true, features = ["json", "blocking"] } serde_json.workspace = true tokio.workspace = true # note: this dependency should _always_ be pinned, prefix the version with an `=` -router-bridge = "=0.6.0+v2.9.0" +router-bridge = "=0.6.1+v2.9.0" [dev-dependencies] anyhow = "1"