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 42 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
169 changes: 165 additions & 4 deletions docs/source/api/apollo-gateway.mdx
Expand Up @@ -100,11 +100,18 @@ const gateway = new ApolloGateway({

###### `supergraphSdl`

`String`
`string | SupergraphSdlHook | SupergraphSdlObject`
</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.
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`: An `async` function that returns an object containing a `supergraphSdl` string as well as a `cleanup` function. The hook accepts an object containing 3 properties:
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
1. `update`: A function which updates the supergraph schema
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
2. `healthCheck`: A function which issues a health check against the subgraphs
3. `getDataSource`: A function which gets a data source for a particular subgraph from the gateway

When `supergraphSdl` is a `SupergraphSdlObject`: An object containing an `initialize` property. `initialize` is an `async` function of the `SupergraphSdlHook` type mentioned directly above.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

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

Expand All @@ -124,7 +131,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,7 +150,9 @@ You can specify any string value for the `name` field, which is used for identif

###### `introspectionHeaders`

`Object | (service: ServiceEndpointDefinition) => Promise<Object> | Object`
**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

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

Expand Down Expand Up @@ -557,3 +566,155 @@ The details of the `fetch` response sent by the subgraph.
</tr>
</tbody>
</table>

## `class IntrospectAndCompose`

The drop-in replacement for `serviceList`. This class is meant to be passed directly to `ApolloGateway`'s `supergraphSdl` constructor option.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

### Methods

#### `constructor`

Returns an initialized `IntrospectAndCompose` instance, which you can then pass to the `supergraphSdl` configuration option to the `ApolloGateway` constructor, like so:
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

```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` will use the data sources constructed by `ApolloGateway`. In order to customize the gateway's data sources, you can proved a [`buildService`](#buildservice) function to the `ApolloGateway` constructor. In the example below, `IntrospectAndCompose` will make authenticated requests to the subgraphs
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
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 which should be treated as a subgraph's unique identifier. It is used for query planning, logging, and reporting metrics to Apollo Studio.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
> For Studio users, subgraph names must also satisfy the following regex when publishing: `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$`.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

</td>
</tr>

<tr>
<td>

###### `introspectionHeaders`

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

An object, or an (optionally) async function returning an object, containing the names and values of HTTP headers that the gateway includes _only_ when making introspection requests to your subgraphs.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

**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` will poll each subgraph at the given interval.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
</td>
</tr>

<tr>
<td>

###### `subgraphHealthCheck`

`boolean`
</td>
<td>

> Note: this only applies to subgraphs that are configured for polling via the `pollIntervalInMs` option.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
Perform 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.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

**This option is the `IntrospectAndCompose` equivalent of `ApolloGateway`'s `serviceHealthCheck` option. If you are using `IntrospectAndCompose`, there is no need to enable `serviceHealthCheck` on your `ApolloGateway` instance.**
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
</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
134 changes: 116 additions & 18 deletions docs/source/gateway.mdx
Expand Up @@ -34,12 +34,12 @@ const supergraphSdl = readFileSync('./supergraph.graphql').toString();
// Initialize an ApolloGateway instance and pass it
// the supergraph schema
const gateway = new ApolloGateway({
supergraphSdl
supergraphSdl,
});

// Pass the ApolloGateway to the ApolloServer constructor
const server = new ApolloServer({
gateway
gateway,
});

server.listen().then(({ url }) => {
Expand All @@ -57,41 +57,139 @@ To learn how to compose your supergraph schema with the Rover CLI, see the [Fede

On startup, the gateway processes your `supergraphSdl`, which includes routing information for your subgraphs. It then begins accepting incoming requests and creates query plans for them that execute across one or more subgraphs.

### Composing with `serviceList`
### Updating the supergraph schema

In the above example, we provide a _static_ supergraph schema to the gateway. This approach requires the gateway to be restarted in order to update the supergraph schema. This is less than ideal for many applications, so we also provide the ability to update the supergraph schema dynamically.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

```js:title=index.js
const { ApolloServer } = require('apollo-server');
const { ApolloGateway } = require('@apollo/gateway');
const { readFile } = require('fs/promises');

let supergraphUpdate;
const gateway = new ApolloGateway({
async supergraphSdl({ update }) {
// `update` is a function which we'll save for later use
supergraphUpdate = update;
return {
supergraphSdl: await readFile('./supergraph.graphql', 'utf-8'),
}
},
});

// Pass the ApolloGateway to the ApolloServer constructor
const server = new ApolloServer({
gateway,
});

server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
```

There are a few things happening here; let's take a look at each of them individually.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

Note that `supergraphSdl` is now an `async` function. This function is only called once when `ApolloServer` initializes the gateway, and has two primary responsibilities:
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
1. Receive the `update` function, which we'll use to update the supergraph schema.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
2. Return the initial supergraph schema which the gateway will use at startup.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

With the `update` function, we can now programatically update the supergraph. Polling, webhooks, and file watchers are all good examples of ways we can go about updating the supergraph.

The code below demonstrates a more complete example using a file watcher. In this example, we'll assume `rover` is updating the `supergraphSdl.graphql` file.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

> We strongly recommend _against_ using `serviceList`. For details, [see below](#limitations-of-servicelist).
```js:title=index.js
const { ApolloServer } = require('apollo-server');
const { ApolloGateway } = require('@apollo/gateway');
const { watch } = require('fs');
const { readFile } = require('fs/promises');

const server = new ApolloServer({
gateway: new ApolloGateway({
async supergraphSdl({ update, healthCheck }) {
// create a file watcher
const watcher = watch('./supergraph.graphql');
// subscribe to file changes
watcher.on('change', async () => {
// update the supergraph schema
try {
const updatedSupergraph = await readFile('./supergraph.graphql', 'utf-8');
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved
// optional health check update to ensure our services are responsive
await healthCheck(updatedSupergraph);
// update the supergraph schema
update(updatedSupergraph);
} catch (e) {
// handle errors that occur during health check or while updating the supergraph schema
console.error(e);
}
});

return {
supergraphSdl: await readFile('./supergraph.graphql', 'utf-8'),
// cleanup is called when the gateway is stopped
async cleanup() {
watcher.close();
}
}
},
}),
});

server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
```

This example is a bit more fleshed out. Let's take a look at what we've added.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

In the `supergraphSdl` callback, we also receive a `healthCheck` function. This allows us to run a health check against each of the services in our future supergraph schema. This is useful for ensuring that our services are responsive and that we don't perform an update when it's unsafe.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

We've also wrapped our call to `update` and `healthCheck` in a `try` block. If an error occurs during either of these, we want to handle this gracefully. In this example, we continue running the existing supergraph schema and log an error.

You might've also noticed we're returning a `cleanup` function. This is a callback that is called when the gateway is stopped. This allows us to cleanly shut down any ongoing processes (such as file watching or polling) when the gateway is shut down via a call to `ApolloServer.stop`. The gateway expects `cleanup` to return a `Promise` and will `await` it before shutting down.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

#### Advanced usage

Your use case may grow to have some complexity which might be better managed within a class that handles the `update` and `healthCheck` functions as well as any additional state. In this case, you may instead provide an object (or class) with an `initialize` function. This function is called just the same as the `supergraphSdl` function discussed above. For a good example of this, check out the [`IntrospectAndCompose` source code](https://github.com/apollographql/federation/blob/main/packages/apollo-gateway/src/IntrospectAndCompose/index.ts).
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

### Composing subgraphs with `IntrospectAndCompose`

> Looking for `serviceList`? `IntrospectAndCompose` is the new drop-in replacement for the `serviceList` option. In the near future, the `serviceList` option will be removed; however, `IntrospectAndCompose` will continue to be supported. Apollo generally recommends approaches that utilize `rover` for managing local composition, though `IntrospectAndCompose` is still useful for various development and testing workflows.
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

> We strongly recommend _against_ using `IntrospectAndCompose` in production. For details, [see below](#limitations-of-introspectandcompose).

Alternatively, you can provide a `serviceList` array to the `ApolloGateway` constructor, like so:
trevor-scheer marked this conversation as resolved.
Show resolved Hide resolved

```js:title=index.js
const { ApolloGateway, IntrospectAndCompose } = require('@apollo/gateway');

const gateway = new ApolloGateway({
serviceList: [
{ name: 'accounts', url: 'http://localhost:4001' },
{ name: 'products', url: 'http://localhost:4002' },
// ...additional subgraphs...
]
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'accounts', url: 'http://localhost:4001' },
{ name: 'products', url: 'http://localhost:4002' },
// ...additional subgraphs...
],
}),
});
```

Each item in the array is an object that specifies the `name` and `url` of one of your subgraphs. You can specify any string value for `name`, which is used primarily for query planner output, error messages, and logging.

On startup, the gateway fetches each subgraph's schema from its `url` and composes those schemas into a supergraph schema. It then begins accepting incoming requests and creates query plans for them that execute across one or more subgraphs.

However, the `serviceList` option has important [limitations](#limitations-of-servicelist).
Additional configuration options can be found in the [`IntrospectAndCompose` API documentation](./api/apollo-gateway#class-introspectandcompose).

#### Limitations of `serviceList`
However, `IntrospectAndCompose` has important [limitations](#limitations-of-introspectandcompose).

The `serviceList` option can sometimes be helpful for local development, but it is strongly discouraged for any other environment. Here are some reasons why:
#### Limitations of `IntrospectAndCompose`

* **Composition might fail.** With `serviceList`, your gateway performs composition dynamically on startup, which requires network communication with each subgraph. If composition fails, your gateway [throws errors](./errors/) and experiences unplanned downtime.
* With `supergraphSdl`, you instead provide a supergraph schema that has _already_ been composed successfully. This prevents composition errors and enables faster startup.
The `IntrospectAndCompose` option can sometimes be helpful for local development, but it is strongly discouraged for any other environment. Here are some reasons why:

* **Composition might fail.** With `IntrospectAndCompose`, your gateway performs composition dynamically on startup, which requires network communication with each subgraph. If composition fails, your gateway [throws errors](./errors/) and experiences unplanned downtime.
* With the static or dynamic `supergraphSdl` configuration, you instead provide a supergraph schema that has _already_ been composed successfully. This prevents composition errors and enables faster startup.
* **Gateway instances might differ.** If you deploy multiple instances of your gateway _while_ deploying updates to your subgraphs, your gateway instances might fetch different schemas from the _same_ subgraph. This can result in sporadic composition failures or inconsistent supergraph schemas between instances.
* When you deploy multiple instances with `supergraphSdl`, you provide the exact same static artifact to each instance, enabling more predictable behavior.

> **We hope to deprecate the `serviceList` option in the coming months**, but we'd love to hear from you if it enables an important use case that either `supergraphSdl` or [managed federation](./managed-federation/overview/) currently doesn't.
>
> Please let us know by [creating an issue](https://github.com/apollographql/federation/issues/new/choose) or [replying to this forum topic](https://community.apollographql.com/t/1053).

## Updating the gateway

> Before updating your gateway's version, check the [changelog](https://github.com/apollographql/federation/blob/main/gateway-js/CHANGELOG.md) for potential breaking changes.
Expand Down
2 changes: 1 addition & 1 deletion docs/source/subgraphs.mdx
Expand Up @@ -197,7 +197,7 @@ The `sdl` field returns your subgraph's schema as an SDL string. This field has
* Unlike introspection, the `sdl` field is _not_ disabled by default in production environments (this is safe if you properly [secure your subgraph](#securing-your-subgraphs)).
* Unlike introspection, the `sdl` field's returned string includes federation-specific directives like `@key`.

Whenever your gateway needs to fetch a subgraph's schema (this occurs only if your gateway uses [the `serviceList` option](./gateway/#composing-with-servicelist)), it uses this field _instead of_ an introspection query so it can obtain federation-specific details.
Whenever your gateway needs to fetch a subgraph's schema (this occurs only if your gateway uses [`IntrospectAndCompose`](./gateway/#composing-subgraphs-with-introspectandcompose)), it uses this field _instead of_ an introspection query so it can obtain federation-specific details.

### `Query._entities`

Expand Down