Skip to content

Commit 2444a2c

Browse files
Merge branch 'dev' into i1g/fix_coprocessor_data_null
2 parents 1c706e2 + 74e9be9 commit 2444a2c

File tree

68 files changed

+716
-145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+716
-145
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
### Add compute pool metrics ([PR #7184](https://github.com/apollographql/router/pull/7184))
2+
3+
The compute job pool is used within the router for compute intensive jobs that should not block the Tokio worker threads.
4+
When this pool becomes saturated it is difficult for users to see why so that they can take action.
5+
This change adds new metrics to help users understand how long jobs are waiting to be processed.
6+
7+
New metrics:
8+
- `apollo.router.compute_jobs.queue_is_full` - A counter of requests rejected because the queue was full.
9+
- `apollo.router.compute_jobs.duration` - A histogram of time spent in the compute pipeline by the job, including the queue and query planning.
10+
- `job.type`: (`QueryPlanning`, `QueryParsing`, `Introspection`)
11+
- `job.outcome`: (`ExecutedOk`, `ExecutedError`, `ChannelError`, `RejectedQueueFull`, `Abandoned`)
12+
- `apollo.router.compute_jobs.queue.wait.duration` - A histogram of time spent in the compute queue by the job.
13+
- `job.type`: (`QueryPlanning`, `QueryParsing`, `Introspection`)
14+
- `apollo.router.compute_jobs.execution.duration` - A histogram of time spent to execute job (excludes time spent in the queue).
15+
- `job.type`: (`QueryPlanning`, `QueryParsing`, `Introspection`)
16+
- `apollo.router.compute_jobs.active_jobs` - A gauge of the number of compute jobs being processed in parallel.
17+
- `job.type`: (`QueryPlanning`, `QueryParsing`, `Introspection`)
18+
19+
By [@carodewig](https://github.com/carodewig) in https://github.com/apollographql/router/pull/7184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### Fix crash when an invalid query plan is generated ([PR #7214](https://github.com/apollographql/router/pull/7214))
2+
3+
When an invalid query plan is generated, the router could panic and crash.
4+
This could happen if there are gaps in the GraphQL validation implementation.
5+
Now, even if there are unresolved gaps, the router will handle it gracefully and reject the request.
6+
7+
By [@goto-bus-stop](https://github.com/goto-bus-stop) in https://github.com/apollographql/router/pull/7214

.config/mise/config.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ rust = "1.85.0"
1212
"cargo:graphql_client_cli" = "0.14.0"
1313
"cargo:cargo-llvm-cov" = "0.6.10"
1414
"cargo:cargo-fuzz" = "0.12.0"
15+
"cargo:typos-cli" = "1.31.1"

Cargo.lock

+13-13
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,7 @@ dependencies = [
13511351
"bitflags 2.6.0",
13521352
"cexpr",
13531353
"clang-sys",
1354-
"itertools 0.10.5",
1354+
"itertools 0.11.0",
13551355
"lazy_static",
13561356
"lazycell",
13571357
"log",
@@ -1946,9 +1946,9 @@ dependencies = [
19461946

19471947
[[package]]
19481948
name = "crossbeam-channel"
1949-
version = "0.5.14"
1949+
version = "0.5.15"
19501950
source = "registry+https://github.com/rust-lang/crates.io-index"
1951-
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
1951+
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
19521952
dependencies = [
19531953
"crossbeam-utils",
19541954
]
@@ -2382,7 +2382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
23822382
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
23832383
dependencies = [
23842384
"libc",
2385-
"windows-sys 0.52.0",
2385+
"windows-sys 0.59.0",
23862386
]
23872387

23882388
[[package]]
@@ -3993,7 +3993,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
39933993
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
39943994
dependencies = [
39953995
"cfg-if",
3996-
"windows-targets 0.48.5",
3996+
"windows-targets 0.52.6",
39973997
]
39983998

39993999
[[package]]
@@ -5149,7 +5149,7 @@ version = "0.13.4"
51495149
source = "registry+https://github.com/rust-lang/crates.io-index"
51505150
checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b"
51515151
dependencies = [
5152-
"heck 0.4.1",
5152+
"heck 0.5.0",
51535153
"itertools 0.13.0",
51545154
"log",
51555155
"multimap 0.10.0",
@@ -5170,7 +5170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
51705170
checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
51715171
dependencies = [
51725172
"anyhow",
5173-
"itertools 0.10.5",
5173+
"itertools 0.11.0",
51745174
"proc-macro2",
51755175
"quote",
51765176
"syn 2.0.90",
@@ -5291,7 +5291,7 @@ dependencies = [
52915291
"once_cell",
52925292
"socket2",
52935293
"tracing",
5294-
"windows-sys 0.52.0",
5294+
"windows-sys 0.59.0",
52955295
]
52965296

52975297
[[package]]
@@ -5912,7 +5912,7 @@ dependencies = [
59125912
"errno",
59135913
"libc",
59145914
"linux-raw-sys 0.4.14",
5915-
"windows-sys 0.52.0",
5915+
"windows-sys 0.59.0",
59165916
]
59175917

59185918
[[package]]
@@ -5925,7 +5925,7 @@ dependencies = [
59255925
"errno",
59265926
"libc",
59275927
"linux-raw-sys 0.9.3",
5928-
"windows-sys 0.52.0",
5928+
"windows-sys 0.59.0",
59295929
]
59305930

59315931
[[package]]
@@ -6474,7 +6474,7 @@ dependencies = [
64746474
"cfg-if",
64756475
"libc",
64766476
"psm",
6477-
"windows-sys 0.52.0",
6477+
"windows-sys 0.59.0",
64786478
]
64796479

64806480
[[package]]
@@ -6666,7 +6666,7 @@ dependencies = [
66666666
"getrandom 0.3.1",
66676667
"once_cell",
66686668
"rustix 1.0.3",
6669-
"windows-sys 0.52.0",
6669+
"windows-sys 0.59.0",
66706670
]
66716671

66726672
[[package]]
@@ -7739,7 +7739,7 @@ version = "0.1.9"
77397739
source = "registry+https://github.com/rust-lang/crates.io-index"
77407740
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
77417741
dependencies = [
7742-
"windows-sys 0.48.0",
7742+
"windows-sys 0.59.0",
77437743
]
77447744

77457745
[[package]]

DEVELOPMENT.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ cargo build --profile release-dhat --features dhat-heap
106106

107107
This will create a router in `./target/release-dhat`, which can be run with:
108108
```shell
109-
cargo run --profile release-dhat --feautures dhat-heap -- -s ./apollo-router/testing_schema.graphql -c router.yaml
109+
cargo run --profile release-dhat --features dhat-heap -- -s ./apollo-router/testing_schema.graphql -c router.yaml
110110
```
111111

112112
When you run your binary, on termination you will get `dhat-heap.json` and/or `dhat-ad-hoc.json` files which can

RELEASE_CHECKLIST.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ Start following the steps below to start a release PR. The process is **not ful
283283
git push --set-upstream "${APOLLO_ROUTER_RELEASE_GIT_ORIGIN}" "prep-${APOLLO_ROUTER_RELEASE_VERSION}"
284284
```
285285
286-
15. Programatically create a small temporary file called `this_release.md` with the changelog details of _precisely this release_ from the `CHANGELOG.md`:
286+
15. Programmatically create a small temporary file called `this_release.md` with the changelog details of _precisely this release_ from the `CHANGELOG.md`:
287287
288288
> Note: This file could totally be created by the `xtask` if we merely decide convention for it and whether we want it checked in or not. It will be used again later in process and, in theory, by CI. Definitely not suggesting this should live on as regex.
289289

apollo-federation/src/link/link_spec_definition.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl LinkSpecDefinition {
156156
// (in practice, our own code can actually handle this as it does not strongly rely on
157157
// that "it should be the first" rule, but that would set a bad example).
158158
// 2. earlier versions (pre-#1875) were always putting that directive on the definition,
159-
// and we wanted to avoid suprising users by changing that for not reason.
159+
// and we wanted to avoid surprising users by changing that for not reason.
160160
//
161161
// So instead, we put the directive on the schema definition unless some extensions exists
162162
// but no definition does (that is, no non-extension elements are populated).

apollo-federation/src/operation/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static NEXT_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(1);
7777
///
7878
/// NOTE: This ID does not ensure that IDs are unique because its internal counter resets on
7979
/// startup. It currently implements `Serialize` for debugging purposes. It should not implement
80-
/// `Deserialize`, and, more specfically, it should not be used for caching until uniqueness is
80+
/// `Deserialize`, and, more specifically, it should not be used for caching until uniqueness is
8181
/// provided (i.e. the inner type is a `Uuid` or the like).
8282
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, serde::Serialize)]
8383
pub(crate) struct SelectionId(usize);
@@ -1324,7 +1324,7 @@ impl SelectionSet {
13241324
/// so we can efficiently generate query plans. In order to prevent the query planner from spending time
13251325
/// exploring those useless __typename options, we "remove" the unnecessary __typename selections from the
13261326
/// operation. Since we need to ensure that the __typename field will still need to be queried, we "tag"
1327-
/// one of the "sibling" selections (using "attachement") to remember that __typename needs to be added
1327+
/// one of the "sibling" selections (using "attachment") to remember that __typename needs to be added
13281328
/// back eventually. The core query planning algorithm will ignore that tag, and because __typename has been
13291329
/// otherwise removed, we'll save any related work. As we build the final query plan, we'll check back for
13301330
/// those "tags" and add back the __typename selections. As this only happen after the query planning
@@ -1698,7 +1698,7 @@ impl SelectionSet {
16981698
///
16991699
/// The final selections are optional. If `path` ends on a leaf field, then no followup
17001700
/// selections would make sense.
1701-
/// When final selections are provided, unecessary fragments will be automatically removed
1701+
/// When final selections are provided, unnecessary fragments will be automatically removed
17021702
/// at the junction between the path and those final selections.
17031703
///
17041704
/// For instance, suppose that we have:
@@ -2144,12 +2144,12 @@ fn compute_aliases_for_non_merging_fields(
21442144
};
21452145
}
21462146
} else {
2147-
// We need to alias the new occurence.
2147+
// We need to alias the new occurrence.
21482148
let alias = gen_alias_name(response_name, &seen_response_names);
21492149

21502150
// Given how we generate aliases, it's is very unlikely that the generated alias will conflict with any of the other response name
21512151
// at the level, but it's theoretically possible. By adding the alias to the seen names, we ensure that in the remote change that
2152-
// this ever happen, we'll avoid the conflict by giving another alias to the followup occurence.
2152+
// this ever happen, we'll avoid the conflict by giving another alias to the followup occurrence.
21532153
let selections = match field.selection_set.as_ref() {
21542154
Some(s) => {
21552155
let mut p = path.clone();

apollo-federation/src/query_graph/graph_path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub(crate) struct SubgraphEnteringEdgeInfo {
257257
///
258258
/// NOTE: This ID does not ensure that IDs are unique because its internal counter resets on
259259
/// startup. It currently implements `Serialize` for debugging purposes. It should not implement
260-
/// `Deserialize`, and, more specfically, it should not be used for caching until uniqueness is
260+
/// `Deserialize`, and, more specifically, it should not be used for caching until uniqueness is
261261
/// provided (i.e. the inner type is a `Uuid` or the like).
262262
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, serde::Serialize)]
263263
pub(crate) struct OverrideId(usize);

apollo-federation/src/query_plan/fetch_dependency_graph.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ impl FetchDependencyGraph {
822822
// 1. is for the same subgraph
823823
// 2. has the same merge_at
824824
// 3. is for the same entity type (we don't reuse nodes for different entities just yet,
825-
// as this can create unecessary dependencies that gets in the way of some optimizations;
825+
// as this can create unnecessary dependencies that gets in the way of some optimizations;
826826
// the final optimizations in `reduceAndOptimize` will however later merge nodes
827827
// on the same subgraph and mergeAt when possible).
828828
// 4. is not part of our conditions or our conditions ancestors
@@ -940,7 +940,7 @@ impl FetchDependencyGraph {
940940
return true;
941941
}
942942

943-
// No risk of inifite loop as the graph is acyclic:
943+
// No risk of infinite loop as the graph is acyclic:
944944
let mut to_check = haystack.clone();
945945
while let Some(next) = to_check.pop() {
946946
for parent in self.parents_of(next) {
@@ -3851,7 +3851,7 @@ fn compute_nodes_for_op_path_element<'a>(
38513851
// If the operation contains other directives or a non-trivial type condition,
38523852
// we need to preserve it and so we add operation.
38533853
// Otherwise, we just skip it as a minor optimization (it makes the subgraph query
3854-
// slighly smaller and on complex queries, it might also deduplicate similar selections).
3854+
// slightly smaller and on complex queries, it might also deduplicate similar selections).
38553855
return Ok(ComputeNodesStackItem {
38563856
tree: &child.tree,
38573857
node_id: stack_item.node_id,

apollo-federation/src/query_plan/fetch_dependency_graph_processor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ impl FetchDependencyGraphProcessor<Option<PlanNode>, DeferredDeferBlock>
302302
// Note that currently `ConditionNode` only works for variables
303303
// (`ConditionNode.condition` is expected to be a variable name and nothing else).
304304
// We could change that, but really, why have a trivial `ConditionNode`
305-
// when we can optimise things righ away.
305+
// when we can optimise things right away.
306306
condition.then_some(value)
307307
}
308308
Conditions::Variables(variables) => {

apollo-federation/src/query_plan/generate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ where
125125
// all plans are guaranteed to be more costly than `initial` anyway.
126126
// Note that save for `initial`,
127127
// we always compute `partialCost` as the pros of exiting some branches early are large enough
128-
// that it outweight computing some costs unecessarily from time to time.
128+
// that it outweigh computing some costs unnecessarily from time to time.
129129
let mut stack = VecDeque::new();
130130
stack.push_back(Partial {
131131
partial_plan: initial,

apollo-federation/src/query_plan/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,17 @@ pub enum QueryPathElement {
247247
Field { response_key: Name },
248248
InlineFragment { type_condition: Name },
249249
}
250+
251+
impl PlanNode {
252+
/// Returns the kind of plan node this is as a human-readable string. Exact output not guaranteed.
253+
fn node_kind(&self) -> &'static str {
254+
match self {
255+
Self::Fetch(_) => "Fetch",
256+
Self::Sequence(_) => "Sequence",
257+
Self::Parallel(_) => "Parallel",
258+
Self::Flatten(_) => "Flatten",
259+
Self::Defer(_) => "Defer",
260+
Self::Condition(_) => "Condition",
261+
}
262+
}
263+
}

apollo-federation/src/query_plan/query_planner.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,11 @@ impl QueryPlanner {
493493
),
494494
Some(PlanNode::Sequence(root_node)) if is_subscription => {
495495
let Some((primary, rest)) = root_node.nodes.split_first() else {
496-
unreachable!("Sequence must have at least one node");
496+
// TODO(@goto-bus-stop): We could probably guarantee this in the type system
497+
bail!("Invalid query plan: Sequence must have at least one node");
497498
};
498499
let PlanNode::Fetch(primary) = primary.clone() else {
499-
unreachable!("Primary node of a subscription is not a Fetch");
500+
bail!("Invalid query plan: Primary node of a subscription is not a Fetch");
500501
};
501502
let rest = PlanNode::Sequence(SequenceNode {
502503
nodes: rest.to_vec(),
@@ -509,9 +510,10 @@ impl QueryPlanner {
509510
))
510511
}
511512
Some(node) if is_subscription => {
512-
unreachable!(
513-
"Unexpected top level PlanNode: '{node:?}' when processing subscription"
514-
)
513+
bail!(
514+
"Invalid query plan for subscription: unexpected {} at root",
515+
node.node_kind()
516+
);
515517
}
516518
Some(PlanNode::Fetch(inner)) => Some(TopLevelPlanNode::Fetch(inner)),
517519
Some(PlanNode::Sequence(inner)) => Some(TopLevelPlanNode::Sequence(inner)),
@@ -628,7 +630,7 @@ fn compute_root_serial_dependency_graph(
628630
// PORT_NOTE: It is unclear if they correct thing to do here is get the next ID, use
629631
// the current ID that is inside the fetch dep graph's ID generator, or to use the
630632
// starting ID. Because this method ensure uniqueness between IDs, this approach was
631-
// taken; however, it could be the case that this causes unforseen issues.
633+
// taken; however, it could be the case that this causes unforeseen issues.
632634
digest.push(std::mem::replace(
633635
&mut fetch_dependency_graph,
634636
new_dep_graph,

apollo-federation/src/query_plan/query_planning_traversal.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ impl<'a: 'b, 'b> QueryPlanningTraversal<'a, 'b> {
640640
// To guarantee that the selection is fully local from the provided vertex/type, we must have:
641641
// - no edge crossing subgraphs from that vertex.
642642
// - the type must be compositeType (mostly just ensuring the selection make sense).
643-
// - everything in the selection must be avaiable in the type (which `rebaseOn` essentially validates).
643+
// - everything in the selection must be available in the type (which `rebaseOn` essentially validates).
644644
// - the selection must not "type-cast" into any abstract type that has inconsistent runtimes acrosse subgraphs. The reason for the
645645
// later condition is that `selection` is originally a supergraph selection, but that we're looking to apply "as-is" to a subgraph.
646646
// But suppose it has a `... on I` where `I` is an interface. Then it's possible that `I` includes "more" types in the supergraph
@@ -913,11 +913,11 @@ impl<'a: 'b, 'b> QueryPlanningTraversal<'a, 'b> {
913913
}
914914

915915
/// Look at how many plans we'd have to generate and if it's "too much"
916-
/// reduce it to something manageable by arbitrarilly throwing out options.
916+
/// reduce it to something manageable by arbitrarily throwing out options.
917917
/// This effectively means that when a query has too many options,
918918
/// we give up on always finding the "best" query plan in favor of an "ok" query plan.
919919
///
920-
/// TODO: currently, when we need to reduce options, we do so somewhat arbitrarilly.
920+
/// TODO: currently, when we need to reduce options, we do so somewhat arbitrarily.
921921
/// More precisely, we reduce the branches with the most options first
922922
/// and then drop the last option of the branch,
923923
/// repeating until we have a reasonable number of plans to consider.
@@ -1338,7 +1338,7 @@ fn test_prune_and_reorder_first_branch() {
13381338
assert_eq!(branches, expected)
13391339
}
13401340
// Either the first branch had strictly more options than the second,
1341-
// so it is still at its correct potition after removing one option…
1341+
// so it is still at its correct position after removing one option…
13421342
assert(
13431343
&["abcdE", "fgh", "ijk", "lmn", "op"],
13441344
&["abcd", "fgh", "ijk", "lmn", "op"],

apollo-federation/src/query_plan/serializable_document.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use serde::Serialize;
1111
///
1212
/// The relevant schema is required to parse from string but not available during deserialization,
1313
/// so this contains a dual (either or both) “string” or “parsed” representation.
14-
/// Accessing the latter is fallible, and requires an explicit initilization step to provide the schema.
14+
/// Accessing the latter is fallible, and requires an explicit initialization step to provide the schema.
1515
#[derive(Clone)]
1616
pub struct SerializableDocument {
1717
serialized: String,

0 commit comments

Comments
 (0)