Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
af7e621
Helm chart: Support providing RollingUpdate maxSurge and maxUnavailab…
theJC Jul 16, 2024
1e6da59
Add changeset
theJC Jul 16, 2024
cc76906
Update condition checking maxSurge and maxUnavailable to hasKey so va…
theJC Jul 16, 2024
2c9b329
Update helm/chart/router/templates/deployment.yaml
theJC Jul 16, 2024
643e2e8
Update comment per PR comment suggestion
theJC Jul 27, 2024
b337feb
chore(federation): fix merged abstract types test (#5796)
dariuszkuc Aug 12, 2024
1d5b86a
Entity cache: reactivate integration tests (#5779)
Geal Aug 13, 2024
0068d68
Entity cache: return cached entities with errors (#5776)
Geal Aug 13, 2024
81ff40d
refactor(federation): added more comments in fetch dependency graph c…
duckki Aug 13, 2024
20c6134
test(federation): added `FetchDependencyGraph::to_dot` method (#5805)
duckki Aug 14, 2024
71962ef
execute supergraph query selector also on events (#5764)
bnjjj Aug 14, 2024
e6252dd
skip caching tests again (#5817)
Geal Aug 14, 2024
7752a1f
improve entity cache documentation (#5574)
Geal Aug 14, 2024
7b8d801
(bug) Trace propagation via header doesn't work (#5802)
BrynCooke Aug 14, 2024
48a0623
Add `format` for trace ID propagation. (#5803)
BrynCooke Aug 14, 2024
9d17023
Ignore non-apollo directives when extracting demand control directive…
tninesling Aug 14, 2024
26e7dbf
fix: make new `tracing.propagation.format` config optional (#5824)
goto-bus-stop Aug 15, 2024
d564b33
Fixed bugs in subgraph jump minimizing optimization (#5820)
TylerBloom Aug 15, 2024
b606051
chore(federation): generate the same fragment names as JS (#5821)
goto-bus-stop Aug 15, 2024
904faa5
chore(federation): coerce hardcoded GraphQL values to match JS (#5819)
goto-bus-stop Aug 15, 2024
ada3920
fix(federation): change `HashMap`/`HashSet` usage to `IndexMap`/`Inde…
sachindshinde Aug 16, 2024
031b350
chore(federation): fixed the error formating of "excessive number of …
duckki Aug 16, 2024
33891e5
fix(federation): use supergraph when parsing requires fieldset (#5823)
dariuszkuc Aug 16, 2024
c141a07
Fix session counting and the reporting of file handle shortage
Aug 16, 2024
6d20709
add a changeset
Aug 16, 2024
853b70c
Remove custom log rate limiting from listener
Aug 16, 2024
d6114d8
Update changeset message to reflect changes
Aug 16, 2024
8fba8e3
Merge branch 'dev' into helm_rollingupdate
Aug 16, 2024
159c7b4
Helm chart: Support providing RollingUpdate maxSurge and maxUnavailab…
Aug 16, 2024
b340bde
Fix session counting and the reporting of file handle shortage (#5834)
Aug 16, 2024
7be82c5
updating with `dev`
tayrrible Aug 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .changesets/exp_geal_entity_cache_documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
### Entity cache preview ([PR #5574](https://github.com/apollographql/router/pull/5574))

#### Support private information caching

The router supports a new `private_id` option that enables separate, private cache entries to be allocated per user for authenticated requests.

When a subgraph returns a `Cache-Control: private` header, the response data shouldn't be cached and shared among users. However, since the router supports request authentication, it can use it to allocate separate cache entries per users.

To enable this, configure the `private_id` to be the name of a key in the request context that contains the data that's used to differentiate users. This option must be paired with a coprocessor or Rhai script to set the value in context.

Example configuration:

```yaml title="router.yaml"
# Enable entity caching globally
preview_entity_cache:
enabled: true
subgraph:
all:
enabled: true
accounts:
private_id: "user_id"
```


To learn more about configuring and customizing private information caching, go to [Private information caching](https://www.apollographql.com/docs/router/configuration/entity-caching/#private-information-caching) docs.

By [@Geal](https://github.com/Geal) in https://github.com/apollographql/router/pull/5574
5 changes: 5 additions & 0 deletions .changesets/feat_geal_return_response_with_errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Entity cache: return cached entities with errors ([PR #5776](https://github.com/apollographql/router/pull/5776))

If we are requesting entities from a subgraph, where some of them are present in cache, and the subgraph is unavailable (ex: network issue), we want to return a response with the entities we got from the cache, other entities nullified, and an error pointing at the paths of unavailable entities.

By [@Geal](https://github.com/Geal) in https://github.com/apollographql/router/pull/5776
6 changes: 6 additions & 0 deletions .changesets/feat_helm_rollingupdate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### Support providing RollingUpdate maxSurge and maxUnavailable values ([Issue #5664](https://github.com/apollographql/router/issues/5664))

RollingUpdate maxSurge and maxUnavailable are commonly used deployment configuration values. This change makes their
values able to be set via the router helm chart.

By [Jon Christiansen](https://github.com/theJC) in https://github.com/apollographql/router/pull/5665
22 changes: 22 additions & 0 deletions .changesets/feat_propagation_format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
### Add `format` for trace ID propagation. ([PR #5803](https://github.com/apollographql/router/pull/5803))

The router now supports specifying the format of trace IDs that are propagated to subgraphs via headers.

You can configure the format with the `format` option:

```yaml
telemetry:
exporters:
tracing:
propagation:
request:
header_name: "my_header"
# Must be in UUID form, with or without dashes
format: uuid
```

Note that incoming requests must be some form of UUID, either with or without dashes.

To learn about supported formats, go to [`request` configuration reference](https://apollographql.com/docs/router/configuration/telemetry/exporters/tracing/overview#request-configuration-reference) docs.

By [@BrynCooke](https://github.com/BrynCooke) in https://github.com/apollographql/router/pull/5803
20 changes: 20 additions & 0 deletions .changesets/fix_bnjjj_fix_supergraph_query_selector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
### Execute supergraph query selector also on events ([PR #5764](https://github.com/apollographql/router/pull/5764))

The `query: root_fields` selector works on `response` stage for events right now but it should also work on `event_response`. This configuration is now working:

```yaml
telemetry:
instrumentation:
events:
supergraph:
OPERATION_LIMIT_INFO:
message: operation limit info
on: event_response
level: info
attributes:
graphql.operation.name: true
query.root_fields:
query: root_fields
```

By [@bnjjj](https://github.com/bnjjj) in https://github.com/apollographql/router/pull/5764
15 changes: 15 additions & 0 deletions .changesets/fix_bryn_remote_spans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### Fix trace propagation via header ([PR #5802](https://github.com/apollographql/router/pull/5802))

The router now correctly propagates trace IDs when using the `propagation.request.header_name` configuration option.

```yaml
exporters:
tracing:
propagation:
request:
header_name: "id_from_header"
```

Previously, trace IDs weren't transferred to the root span of the request, causing spans to be incorrectly attributed to new traces.

By [@BrynCooke](https://github.com/BrynCooke) in https://github.com/apollographql/router/pull/5802
9 changes: 9 additions & 0 deletions .changesets/fix_garypen_fix_sessions_and_handle_reporting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### Fix session counting and the reporting of file handle shortage ([PR #5834](https://github.com/apollographql/router/pull/5834))

Session counting incorrectly included connections to the health check or other non-graphql connections. This is now corrected so that only connections to the main graphql port are counted.

Warnings about file handle shortages are now handled correctly as a global resource.

The listening logic had its own custom rate limiting notifications. This has been removed and log notification is now controlled by the [standard router log rate limiting configuration](https://www.apollographql.com/docs/router/configuration/telemetry/exporters/logging/stdout/#rate_limit)

By [@garypen](https://github.com/garypen) in https://github.com/apollographql/router/pull/5834
126 changes: 126 additions & 0 deletions apollo-federation/src/compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@

use apollo_compiler::ast::Value;
use apollo_compiler::collections::IndexMap;
use apollo_compiler::executable;
use apollo_compiler::schema::Directive;
use apollo_compiler::schema::ExtendedType;
use apollo_compiler::schema::InputValueDefinition;
use apollo_compiler::schema::Type;
use apollo_compiler::validation::Valid;
use apollo_compiler::ExecutableDocument;
use apollo_compiler::Name;
use apollo_compiler::Node;
use apollo_compiler::Schema;
Expand Down Expand Up @@ -281,10 +284,133 @@ pub fn coerce_schema_default_values(schema: &mut Schema) {
}
}

fn coerce_directive_application_values(
schema: &Valid<Schema>,
directives: &mut executable::DirectiveList,
) {
for directive in directives {
let Some(definition) = schema.directive_definitions.get(&directive.name) else {
continue;
};
let directive = directive.make_mut();
for arg in &mut directive.arguments {
let Some(definition) = definition.argument_by_name(&arg.name) else {
continue;
};
let arg = arg.make_mut();
_ = coerce_value(&schema.types, &mut arg.value, &definition.ty);
}
}
}

fn coerce_selection_set_values(
schema: &Valid<Schema>,
selection_set: &mut executable::SelectionSet,
) {
for selection in &mut selection_set.selections {
match selection {
executable::Selection::Field(field) => {
let definition = field.definition.clone(); // Clone so we can mutate `field`.
let field = field.make_mut();
for arg in &mut field.arguments {
let Some(definition) = definition.argument_by_name(&arg.name) else {
continue;
};
let arg = arg.make_mut();
_ = coerce_value(&schema.types, &mut arg.value, &definition.ty);
}
coerce_directive_application_values(schema, &mut field.directives);
coerce_selection_set_values(schema, &mut field.selection_set);
}
executable::Selection::FragmentSpread(frag) => {
let frag = frag.make_mut();
coerce_directive_application_values(schema, &mut frag.directives);
}
executable::Selection::InlineFragment(frag) => {
let frag = frag.make_mut();
coerce_directive_application_values(schema, &mut frag.directives);
coerce_selection_set_values(schema, &mut frag.selection_set);
}
}
}
}

fn coerce_operation_values(schema: &Valid<Schema>, operation: &mut Node<executable::Operation>) {
let operation = operation.make_mut();

for variable in &mut operation.variables {
let variable = variable.make_mut();
let Some(default_value) = &mut variable.default_value else {
continue;
};

// On error, the default value is invalid. This would have been caught by validation.
// In schemas, we explicitly remove the default value if it's invalid, to match the JS
// query planner behaviour.
// In queries, I hope we can just reject queries with invalid default values instead of
// silently doing the wrong thing :)
_ = coerce_value(&schema.types, default_value, &variable.ty);
}

coerce_selection_set_values(schema, &mut operation.selection_set);
}

pub fn coerce_executable_values(schema: &Valid<Schema>, document: &mut ExecutableDocument) {
if let Some(operation) = &mut document.operations.anonymous {
coerce_operation_values(schema, operation);
}
for operation in document.operations.named.values_mut() {
coerce_operation_values(schema, operation);
}
}

/// Applies default value coercion and removes non-semantic directives so that
/// the apollo-rs serialized output of the schema matches the result of
/// `printSchema(buildSchema()` in graphql-js.
pub fn make_print_schema_compatible(schema: &mut Schema) {
remove_non_semantic_directives(schema);
coerce_schema_default_values(schema);
}

#[cfg(test)]
mod tests {
use apollo_compiler::validation::Valid;
use apollo_compiler::ExecutableDocument;
use apollo_compiler::Schema;

use super::coerce_executable_values;

fn parse_and_coerce(schema: &Valid<Schema>, input: &str) -> String {
let mut document = ExecutableDocument::parse(schema, input, "test.graphql").unwrap();
coerce_executable_values(schema, &mut document);
document.to_string()
}

#[test]
fn coerces_list_values() {
let schema = Schema::parse_and_validate(
r#"
type Query {
test(
bools: [Boolean],
ints: [Int],
strings: [String],
floats: [Float],
): Int
}
"#,
"schema.graphql",
)
.unwrap();

insta::assert_snapshot!(parse_and_coerce(&schema, r#"
{
test(bools: true, ints: 1, strings: "string", floats: 2.0)
}
"#), @r#"
{
test(bools: [true], ints: [1], strings: ["string"], floats: [2.0])
}
"#);
}
}
38 changes: 14 additions & 24 deletions apollo-federation/src/link/cost_spec_definition.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::collections::HashMap;

use apollo_compiler::ast::Argument;
use apollo_compiler::ast::Directive;
use apollo_compiler::collections::IndexMap;
use apollo_compiler::name;
use apollo_compiler::schema::Component;
use apollo_compiler::schema::EnumType;
Expand Down Expand Up @@ -41,14 +40,11 @@ macro_rules! propagate_demand_control_directives {
subgraph_schema: &FederationSchema,
source: &$directives_ty,
dest: &mut $directives_ty,
original_directive_names: &HashMap<Name, Name>,
original_directive_names: &IndexMap<Name, Name>,
) -> Result<(), FederationError> {
let cost_directive_name = original_directive_names.get(&COST_DIRECTIVE_NAME_IN_SPEC);
if let Some(cost_directive) = source.get(
cost_directive_name
.unwrap_or(&COST_DIRECTIVE_NAME_IN_SPEC)
.as_str(),
) {
let cost_directive = cost_directive_name.and_then(|name| source.get(name.as_str()));
if let Some(cost_directive) = cost_directive {
dest.push($wrap_ty(self.cost_directive(
subgraph_schema,
cost_directive.arguments.clone(),
Expand All @@ -57,11 +53,9 @@ macro_rules! propagate_demand_control_directives {

let list_size_directive_name =
original_directive_names.get(&LIST_SIZE_DIRECTIVE_NAME_IN_SPEC);
if let Some(list_size_directive) = source.get(
list_size_directive_name
.unwrap_or(&LIST_SIZE_DIRECTIVE_NAME_IN_SPEC)
.as_str(),
) {
let list_size_directive =
list_size_directive_name.and_then(|name| source.get(name.as_str()));
if let Some(list_size_directive) = list_size_directive {
dest.push($wrap_ty(self.list_size_directive(
subgraph_schema,
list_size_directive.arguments.clone(),
Expand All @@ -80,14 +74,12 @@ macro_rules! propagate_demand_control_directives_to_position {
subgraph_schema: &mut FederationSchema,
source: &Node<$source_ty>,
dest: &$dest_ty,
original_directive_names: &HashMap<Name, Name>,
original_directive_names: &IndexMap<Name, Name>,
) -> Result<(), FederationError> {
let cost_directive_name = original_directive_names.get(&COST_DIRECTIVE_NAME_IN_SPEC);
if let Some(cost_directive) = source.directives.get(
cost_directive_name
.unwrap_or(&COST_DIRECTIVE_NAME_IN_SPEC)
.as_str(),
) {
let cost_directive =
cost_directive_name.and_then(|name| source.directives.get(name.as_str()));
if let Some(cost_directive) = cost_directive {
dest.insert_directive(
subgraph_schema,
Component::from(
Expand All @@ -98,11 +90,9 @@ macro_rules! propagate_demand_control_directives_to_position {

let list_size_directive_name =
original_directive_names.get(&LIST_SIZE_DIRECTIVE_NAME_IN_SPEC);
if let Some(list_size_directive) = source.directives.get(
list_size_directive_name
.unwrap_or(&LIST_SIZE_DIRECTIVE_NAME_IN_SPEC)
.as_str(),
) {
let list_size_directive =
list_size_directive_name.and_then(|name| source.directives.get(name.as_str()));
if let Some(list_size_directive) = list_size_directive {
dest.insert_directive(
subgraph_schema,
Component::from(self.list_size_directive(
Expand Down
10 changes: 5 additions & 5 deletions apollo-federation/src/link/database.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::Arc;

use apollo_compiler::ast::Directive;
use apollo_compiler::ast::DirectiveLocation;
use apollo_compiler::collections::IndexMap;
use apollo_compiler::schema::DirectiveDefinition;
use apollo_compiler::ty;
use apollo_compiler::Schema;
Expand Down Expand Up @@ -46,10 +46,10 @@ pub fn links_metadata(schema: &Schema) -> Result<Option<LinksMetadata>, LinkErro
// all of the @link usages (starting with the bootstrapping one) and extract their metadata.
let link_name_in_schema = &bootstrap_directive.name;
let mut links = Vec::new();
let mut by_identity = HashMap::new();
let mut by_name_in_schema = HashMap::new();
let mut types_by_imported_name = HashMap::new();
let mut directives_by_imported_name = HashMap::new();
let mut by_identity = IndexMap::default();
let mut by_name_in_schema = IndexMap::default();
let mut types_by_imported_name = IndexMap::default();
let mut directives_by_imported_name = IndexMap::default();
let link_applications = schema
.schema_definition
.directives
Expand Down
10 changes: 5 additions & 5 deletions apollo-federation/src/link/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::collections::HashMap;
use std::fmt;
use std::str;
use std::sync::Arc;

use apollo_compiler::ast::Directive;
use apollo_compiler::ast::Value;
use apollo_compiler::collections::IndexMap;
use apollo_compiler::name;
use apollo_compiler::schema::Component;
use apollo_compiler::InvalidNameError;
Expand Down Expand Up @@ -387,10 +387,10 @@ pub struct LinkedElement {
#[derive(Default, Eq, PartialEq, Debug)]
pub struct LinksMetadata {
pub(crate) links: Vec<Arc<Link>>,
pub(crate) by_identity: HashMap<Identity, Arc<Link>>,
pub(crate) by_name_in_schema: HashMap<Name, Arc<Link>>,
pub(crate) types_by_imported_name: HashMap<Name, (Arc<Link>, Arc<Import>)>,
pub(crate) directives_by_imported_name: HashMap<Name, (Arc<Link>, Arc<Import>)>,
pub(crate) by_identity: IndexMap<Identity, Arc<Link>>,
pub(crate) by_name_in_schema: IndexMap<Name, Arc<Link>>,
pub(crate) types_by_imported_name: IndexMap<Name, (Arc<Link>, Arc<Import>)>,
pub(crate) directives_by_imported_name: IndexMap<Name, (Arc<Link>, Arc<Import>)>,
}

impl LinksMetadata {
Expand Down
Loading