Skip to content
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

feat(gateway): Implement new supergraphSdl() config option for dynamic gateway updates #1246

Merged
merged 87 commits into from Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from 84 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
c2f2e68
Initial update of types, introduce deprecation warnings and prelim TODOs
trevor-scheer Nov 24, 2021
78a6e51
Implementation and tests
trevor-scheer Nov 25, 2021
b7dfbac
Types and signature cleanup
trevor-scheer Nov 29, 2021
e7786a6
Implement serviceList shim
trevor-scheer Dec 2, 2021
748d433
Use createHash from apollo-graphql
trevor-scheer Dec 2, 2021
f700641
Refactor health checks and provide external health check hook to new …
trevor-scheer Dec 3, 2021
db77d2f
Fix regex
trevor-scheer Dec 3, 2021
3e3aa08
Fix tests
trevor-scheer Dec 4, 2021
8723c5f
add state to prevent extra polling after cleanup
trevor-scheer Dec 7, 2021
8bce79f
Prevent re-entrant calls to update callback
trevor-scheer Dec 9, 2021
2f67f2d
Catch unexpected state case and throw
trevor-scheer Dec 9, 2021
07ac065
Add test for invalid update, fix uncovered bug
trevor-scheer Dec 9, 2021
559ed47
Handle update failures gracefully, address polling not finished bug w…
trevor-scheer Dec 9, 2021
eeee2e6
Add missing file
trevor-scheer Dec 9, 2021
cde70c2
Rename to IntrospectAndCompose
trevor-scheer Dec 9, 2021
212b67d
Migrate related file into legacy folder
trevor-scheer Dec 9, 2021
35a9189
Docs WIP
trevor-scheer Dec 10, 2021
97f6eca
Brief intermission to adjust buildService implementation...
trevor-scheer Dec 17, 2021
8731e5a
More docs
trevor-scheer Dec 17, 2021
e811777
Merge branch 'release-gateway-0.45.0' into trevor/improve-supergraphSdl
trevor-scheer Dec 17, 2021
e1d081c
Fix docs?
trevor-scheer Dec 17, 2021
1c49051
Use createHash implementation safe for non-node envs
trevor-scheer Dec 20, 2021
7f8377e
Fix broken links
trevor-scheer Dec 20, 2021
b5fe3fd
Merge branch 'version-0.x' into trevor/improve-supergraphSdl
trevor-scheer Jan 3, 2022
144e0cd
Add example using buildService
trevor-scheer Jan 3, 2022
5221b99
Add parens for clarity
trevor-scheer Jan 3, 2022
e9e191e
docs tweak
trevor-scheer Jan 3, 2022
773578d
Use fs/promises for file read example
trevor-scheer Jan 3, 2022
9a284d5
Add clarity around subgraph names
trevor-scheer Jan 3, 2022
399a7d1
remove extraneous note
trevor-scheer Jan 3, 2022
c0b3c40
Implement object.initialize behavior for supergraphSdl property
trevor-scheer Jan 3, 2022
961c36e
move out of legacy directory
trevor-scheer Jan 3, 2022
0605407
remove waitUntil, use resolvable
trevor-scheer Jan 3, 2022
497c1de
missed a spot
trevor-scheer Jan 3, 2022
1eb06b9
Update usage recommendations
trevor-scheer Jan 3, 2022
3edaf0d
Remove buildService warning/deprecation
trevor-scheer Jan 3, 2022
36f9ded
Only cleanup user fns in appropriate states
trevor-scheer Jan 3, 2022
24ae881
Add healthCheck capability to IntrospectAndCompose
trevor-scheer Jan 4, 2022
ef82f49
grammar tweak
trevor-scheer Jan 5, 2022
eddf8eb
consistent utf-8
trevor-scheer Jan 5, 2022
d4fcb52
dont pull initialize function off of object, breaks 'this' usages int…
trevor-scheer Jan 5, 2022
4f06450
use resolvable in places
trevor-scheer Jan 5, 2022
55f1b44
Use IntrospectAndCompose internally (under the hood swap for serviceL…
trevor-scheer Jan 5, 2022
c7cdf4c
Big checkpoint, maybe just localServiceList to deal with?
trevor-scheer Jan 6, 2022
143f03a
Remove composition from gateway, more cleanup, local compose in a sep…
trevor-scheer Jan 6, 2022
c139198
cleanup, move things around
trevor-scheer Jan 7, 2022
484d182
missed a few spots
trevor-scheer Jan 7, 2022
29305ca
docs updates
trevor-scheer Jan 7, 2022
e999f2a
missed a docs suggestion
trevor-scheer Jan 7, 2022
64b8bd5
update codegen config
trevor-scheer Jan 7, 2022
eecd5e9
Merge branch 'version-0.x' into trevor/improve-supergraphSdl
trevor-scheer Jan 7, 2022
2eaaab9
only need one Fixture def
trevor-scheer Jan 7, 2022
97b6561
unfocus test and address failures
trevor-scheer Jan 7, 2022
556a4e1
fix tsdoc
trevor-scheer Jan 7, 2022
4666916
update and use predicates
trevor-scheer Jan 7, 2022
4dffaab
rename / cleanup
trevor-scheer Jan 7, 2022
53b00d2
reorder if elses for simplicity
trevor-scheer Jan 7, 2022
8df89e7
protect against invalid cleanup property
trevor-scheer Jan 7, 2022
f2a0e2f
update comments on external hook functions
trevor-scheer Jan 7, 2022
437edd6
rename createAndCacheDataSource
trevor-scheer Jan 7, 2022
83f5d34
update comment
trevor-scheer Jan 7, 2022
c546ce5
export useful types
trevor-scheer Jan 7, 2022
0c471c5
Add deprecation warning for schemaConfigDeliveryEndpoint option (unre…
trevor-scheer Jan 7, 2022
4e6049c
deprecate experimental_pollInterval
trevor-scheer Jan 7, 2022
3b03867
rename fn to match filename
trevor-scheer Jan 7, 2022
45c9cda
reference new supergraph managers in warnings. export LocalCompose
trevor-scheer Jan 7, 2022
547d02c
Document setting gateway poll interval
Jan 6, 2022
ad8121d
Merge pull request #1366 from StephenBarlow/sb/docs-poll-interval
Jan 7, 2022
3a301d3
Update gateway-js/src/__tests__/integration/networkRequests.test.ts
trevor-scheer Jan 8, 2022
6cfae46
Merge branch 'version-0.x' into trevor/improve-supergraphSdl
trevor-scheer Jan 10, 2022
49200f6
expand on IntrospectAndCompose description
trevor-scheer Jan 10, 2022
95e6caa
remove failure hook from config base
trevor-scheer Jan 10, 2022
5158be7
update deprecation comments
trevor-scheer Jan 10, 2022
c5dcc7a
Add clarifying comment to uplinkEndpoints option
trevor-scheer Jan 10, 2022
fa7dc25
clarify endpoints comment
trevor-scheer Jan 10, 2022
adcab86
No need to log and rethrow on init failure, just throw
trevor-scheer Jan 10, 2022
9d321f8
rename performCleanup fn
trevor-scheer Jan 10, 2022
2198c42
handle stopping case
trevor-scheer Jan 10, 2022
7b7101d
update error message on bad call to stop
trevor-scheer Jan 10, 2022
2a63f07
Remove unrefs and use clearTimeout instead of clearInterval
trevor-scheer Jan 10, 2022
335553f
Update comment for LegacyFetcher
trevor-scheer Jan 10, 2022
2ba31fe
rename experimental_didUpdateComposition to didUpdateSupergraph
trevor-scheer Jan 10, 2022
01761a0
update types
trevor-scheer Jan 10, 2022
7ad0ac1
changelog entry
trevor-scheer Jan 10, 2022
59e9f55
keep it experimental
trevor-scheer Jan 10, 2022
d49dcf9
remove extraneous work being done around schema objects, no longer ne…
trevor-scheer Jan 10, 2022
fd995bb
changelog tweaks
trevor-scheer Jan 10, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions codegen.yml
Expand Up @@ -4,8 +4,8 @@ schema: [
"https://outofbandreporter.api.apollographql.com/",
]
documents:
- gateway-js/src/loadSupergraphSdlFromStorage.ts
- gateway-js/src/outOfBandReporter.ts
- gateway-js/src/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts
- gateway-js/src/supergraphManagers/UplinkFetcher/outOfBandReporter.ts
generates:
gateway-js/src/__generated__/graphqlTypes.ts:
plugins:
Expand Down
176 changes: 172 additions & 4 deletions docs/source/api/apollo-gateway.mdx
Expand Up @@ -100,11 +100,20 @@ const gateway = new ApolloGateway({

###### `supergraphSdl`

`String`
`string | SupergraphSdlHook | SupergraphManager`
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
</td>
<td>

trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
A [supergraph schema](../#federated-schemas) ([generated with the Rover CLI](https://www.apollographql.com/docs/rover/supergraphs/#composing-a-supergraph-schema)) that's composed from your subgraph schemas. The supergraph schema includes directives that specify routing information for each subgraph.
You provide your supergraph schema to the gateway with this option. You can provide it as a `string`, via a `SupergraphSdlHook`, or via a `SupergraphManager`.

**When `supergraphSdl` is a `string`:** A [supergraph schema](../#federated-schemas) ([generated with the Rover CLI](https://www.apollographql.com/docs/rover/supergraphs/#composing-a-supergraph-schema)) that's composed from your subgraph schemas. The supergraph schema includes directives that specify routing information for each subgraph.

**When `supergraphSdl` is a `SupergraphSdlHook`:** This is an `async` function that returns an object containing a `supergraphSdl` string as well as a `cleanup` function. The hook accepts an object containing the following properties:
- `update`: A function that updates the supergraph schema
- `healthCheck`: A function that issues a health check against the subgraphs
- `getDataSource`: A function that gets a data source for a particular subgraph from the gateway

**When `supergraphSdl` is a `SupergraphManager`:** An object containing an `initialize` property. `initialize` is an `async` function of the `SupergraphSdlHook` type described directly above.

**If you are using managed federation,** do not provide this field.

Expand All @@ -124,7 +133,7 @@ A [supergraph schema](../#federated-schemas) ([generated with the Rover CLI](htt
</td>
<td>

**This option is discouraged in favor of [`supergraphSdl`](#supergraphsdl).**
**This option is deprecated in favor of the drop-in replacement, [`IntrospectAndCompose`](#class-introspectandcompose).**
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

An array of objects that each specify the `name` and `url` of one subgraph in your federated graph. On startup, the gateway uses this array to obtain your subgraph schemas via introspection and compose a supergraph schema.

Expand All @@ -143,10 +152,12 @@ You can specify any string value for the `name` field, which is used for identif

###### `introspectionHeaders`

`Object | (service: ServiceEndpointDefinition) => Promise<Object> | Object`
`Object | (service: ServiceEndpointDefinition) => (Promise<Object> | Object)`
</td>
<td>

**This option is deprecated in favor of the drop-in replacement, [`IntrospectAndCompose`](#class-introspectandcompose).**

An object (or an optionally async function _returning_ an object) that contains the names and values of HTTP headers that the gateway includes _only_ when making introspection requests to your subgraphs.

**If you are using managed federation,** do not provide this field.
Expand Down Expand Up @@ -557,3 +568,160 @@ The details of the `fetch` response sent by the subgraph.
</tr>
</tbody>
</table>

## `class IntrospectAndCompose`

`IntrospectAndCompose` is a development tool for fetching and composing subgraph SDL into a supergraph for your gateway. Given a list of subgraphs and their URLs, `IntrospectAndCompose` will issue queries for their SDL, compose them into a supergraph, and provide that supergraph to the gateway. It can also be configured to update via polling and perform subgraph health checks to ensure that supergraphs are updated safely. `IntrospectAndCompose` implements the `SupergraphManager` interface and is passed in to `ApolloGateway`'s `supergraphSdl` constructor option.

> `IntrospectAndCompose` is the drop-in replacement for `serviceList`.

### Methods

#### `constructor`

Returns an initialized `IntrospectAndCompose` instance, which you can then pass to the `supergraphSdl` configuration option of the `ApolloGateway` constructor, like so:

```javascript{3-7}
const server = new ApolloServer({
gateway: new ApolloGateway({
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
// ...
],
}),
}),
});
```

Takes an `options` object as a parameter. Supported properties of this object are described below.

##### Examples

###### Providing a `subgraphs` list and headers to authorize introspection

```js
const gateway = new ApolloGateway({
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'products', url: 'https://products-service.dev/graphql',
{ name: 'reviews', url: 'https://reviews-service.dev/graphql' },
],
introspectionHeaders: {
Authorization: 'Bearer abc123'
},
}),
});
```

###### Configuring the subgraph fetcher

`IntrospectAndCompose` uses the data sources constructed by `ApolloGateway`. To customize the gateway's data sources, you can provide a [`buildService`](#buildservice) function to the `ApolloGateway` constructor. In the example below, `IntrospectAndCompose` makes authenticated requests to the subgraphs
via the `AuthenticatedDataSource`s that we construct in the gateway's `buildService` function.

```js
const gateway = new ApolloGateway({
buildService({ name, url }) {
return new AuthenticatedDataSource({ url });
},
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'products', url: 'https://products-service.dev/graphql',
{ name: 'reviews', url: 'https://reviews-service.dev/graphql' },
],
}),
});
```

##### Options

<table class="field-table">
<thead>
<tr>
<th>Name /<br/>Type</th>
<th>Description</th>
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
</tr>
</thead>

<tbody>

<tr>
<td>

###### `subgraphs`

`Array<ServiceEndpointDefinition>`
</td>
<td>

An array of objects that each specify the `name` and `url` of one subgraph in your federated graph. On startup, `IntrospectAndCompose` uses this array to obtain your subgraph schemas via introspection and compose a supergraph schema.

The `name` field is a string that should be treated as a subgraph's unique identifier. It is used for query planning, logging, and reporting metrics to Apollo Studio.
> For Studio users, subgraph names **must:**
- Begin with a letter (capital or lowercase)
- Include only letters, numbers, underscores (_), and hyphens (-)
- Have a maximum of 64 characters

</td>
</tr>

<tr>
<td>

###### `introspectionHeaders`

`Object | (service: ServiceEndpointDefinition) => (Promise<Object> | Object)`
</td>
<td>

An object (or an optionally async function _returning_ an object)that contains the names and values of HTTP headers that the gateway includes _only_ when making introspection requests to your subgraphs.

**If you define a [`buildService`](#buildservice) function in your `ApolloGateway` config, ** specify these headers in that function instead of providing this option. This ensures that your `buildService` function doesn't inadvertently overwrite the values of any headers you provide here.
</td>
</tr>

<tr>
<td>

###### `pollIntervalInMs`

`number`
</td>
<td>

Specify this option to enable supergraph updates via subgraph polling. `IntrospectAndCompose` polls each subgraph at the given interval.
</td>
</tr>

<tr>
<td>

###### `subgraphHealthCheck`

`boolean`
</td>
<td>

> This option applies only to subgraphs that are configured for polling via the `pollIntervalInMs` option.
If `true`, the gateway performs a health check on each subgraph before performing a supergraph update. Errors during health checks will result in skipping the supergraph update, but polling will continue. The health check is a simple GraphQL query (`query __ApolloServiceHealthCheck__ { __typename }`) to ensure that subgraphs are reachable and can successfully respond to GraphQL requests.

**This option is the `IntrospectAndCompose` equivalent of `ApolloGateway`'s `serviceHealthCheck` option. If you are using `IntrospectAndCompose`, enabling `serviceHealthCheck` on your `ApolloGateway` instance has no effect.**
</td>
</tr>

<tr>
<td>

###### `logger`

[`Logger`](https://github.com/apollographql/apollo-server/blob/main/packages/apollo-server-types/src/index.ts#L166-L172)
</td>
<td>

An object to use for logging in place of `console`. If provided, this object must implement all methods of [the `Logger` interface](https://github.com/apollographql/apollo-server/blob/main/packages/apollo-server-types/src/index.ts#L166-L172).

`IntrospectAndCompose` doesn't share the same logger as the `ApolloGateway` it's configured with. In most cases, you probably want to pass the same logger to both `ApolloGateway` and `IntrospectAndCompose`.
</td>
</tr>

</tbody>
</table>
6 changes: 3 additions & 3 deletions docs/source/entities.mdx
Expand Up @@ -391,11 +391,11 @@ We're done! `Bill` now originates in a new subgraph, and it was resolvable durin

</ExpansionPanel>

<ExpansionPanel title="With serviceList">
<ExpansionPanel title="With `IntrospectAndCompose`">

> ⚠️ We strongly recommend _against_ using `serviceList`. For details, see [Limitations of `serviceList`](./gateway/#limitations-of-servicelist).
> ⚠️ We strongly recommend _against_ using `IntrospectAndCompose` in production. For details, see [Limitations of `IntrospectAndCompose`](./gateway/#limitations-of-introspectandcompose).

When you provide a `serviceList` to `ApolloGateway`, it performs composition _itself_ on startup after fetching all of your subgraph schemas. If this runtime composition fails, the gateway fails to start up, resulting in downtime.
When you provide `IntrospectAndCompose` to `ApolloGateway`, it performs composition _itself_ on startup after fetching all of your subgraph schemas. If this runtime composition fails, the gateway fails to start up, resulting in downtime.

To minimize downtime for your graph, you need to make sure all of your subgraph schemas successfully compose whenever your gateway starts up. When migrating an entity, this requires a **coordinated deployment** of your modified subgraphs and a restart of the gateway itself.

Expand Down