Skip to content

Commit

Permalink
docs and such
Browse files Browse the repository at this point in the history
  • Loading branch information
glasser committed Aug 23, 2021
1 parent 37e32c6 commit 2c375f1
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 83 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The version headers in this history reflect the versions of Apollo Server itself

## vNEXT

- `apollo-server-core`: Previously, only the batteries-included `apollo-server` package supported a graceful shutdown. Now the integrations support it as well, if you tell your `ApolloServer` which HTTP server to drain with the new `ApolloServerPluginDrainHttpServer` plugin. This plugin implements a new `drainServer` plugin hook. For `apollo-server-hapi` you can use `ApolloServerPluginStopHapiServer` instead. [PR #5635](https://github.com/apollographql/apollo-server/pull/5635)
- `apollo-server-core`: Fix `experimental_approximateDocumentStoreMiB` option, which seems to have never worked before. [PR #5629](https://github.com/apollographql/apollo-server/pull/5629)
- `apollo-server-core`: Only register `SIGINT` and `SIGTERM` handlers once the server successfully starts up; trying to call `stop` on a server that hasn't successfully started had undefined behavior. By default, don't register the handlers in serverless integrations, which don't have the same lifecycle as non-serverless integrations (eg, there's no explicit `start` call); you can still explicitly set `stopOnTerminationSignals` to override this default. [PR #5639](https://github.com/apollographql/apollo-server/pull/5639)

Expand Down
1 change: 1 addition & 0 deletions docs/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ module.exports = {
'api/plugin/usage-reporting',
'api/plugin/schema-reporting',
'api/plugin/inline-trace',
'api/plugin/drain-http-server',
'api/plugin/cache-control',
'api/plugin/landing-pages',
],
Expand Down
34 changes: 18 additions & 16 deletions docs/source/api/apollo-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,22 +517,22 @@ The `start` method triggers the following actions:

## `stop`

`ApolloServer.stop()` is an async method that tells all of Apollo Server's background tasks to complete. It calls and awaits all [`serverWillStop` plugin handlers](../integrations/plugins-event-reference/#serverwillstop) (including the [usage reporting plugin](./plugin/usage-reporting/)'s handler, which sends a final usage report to Apollo Studio). This method takes no arguments. You should only call it after [`start()`](#start) returns successfully (or [`listen()`](#listen) if you're using the batteries-included `apollo-server` package).
`ApolloServer.stop()` is an async method that tells all of Apollo Server's background tasks to complete. Specifically, it:

If your server is a [federated gateway](https://www.apollographql.com/docs/federation/gateway/), `stop` also stops gateway-specific background activities, such as polling for updated service configuration.
- Calls and awaits all [`drainServer` plugin handlers](../integrations/plugins-event-reference/#drainserver). These should generally:
* Stop listening for new connections
* Closes idle connections (i.e., connections with no current HTTP request)
* Closes active connections whenever they become idle
* Waits for all connections to be closed
* After a grace period, if any connections remain active, forcefully close them.
If you're using the batteries-included `apollo-server` package, it does this by default. (You can configure the grace period with the [`stopGracePeriodMillis` constructor option](#stopgraceperiodmillis).) Otherwise, you can use the [drain HTTP server plugin](./plugin/drain-http-server/) to drain your HTTP server.
- Transitions the server to a state where it will not start executing more GraphQL operations.
- Calls and awaits all [`serverWillStop` plugin handlers](../integrations/plugins-event-reference/#serverwillstop) (including the [usage reporting plugin](./plugin/usage-reporting/)'s handler, which sends a final usage report to Apollo Studio).
- If your server is a [federated gateway](https://www.apollographql.com/docs/federation/gateway/), `stop` also stops gateway-specific background activities, such as polling for updated service configuration.

In some circumstances, Apollo Server calls `stop` automatically when the process receives a `SIGINT` or `SIGTERM` signal. See the [`stopOnTerminationSignals` constructor option](#stoponterminationsignals) for details.

If you're using the `apollo-server` package (which handles setting up an HTTP server for you), this method first stops the HTTP server. Specifically, it:

* Stops listening for new connections
* Closes idle connections (i.e., connections with no current HTTP request)
* Closes active connections whenever they become idle
* Waits for all connections to be closed

If any connections remain active after a grace period (10 seconds by default), Apollo Server forcefully closes those connections. You can configure this grace period with the [`stopGracePeriodMillis` constructor option](#stopgraceperiodmillis).
This method takes no arguments. You should only call it after [`start()`](#start) returns successfully (or [`listen()`](#listen) if you're using the batteries-included `apollo-server` package).

If you're using a [middleware package](../integrations/middleware/) instead of `apollo-server`, you should stop your HTTP server before calling `ApolloServer.stop()`.
In some circumstances, Apollo Server calls `stop` automatically when the process receives a `SIGINT` or `SIGTERM` signal. See the [`stopOnTerminationSignals` constructor option](#stoponterminationsignals) for details.

## Framework-specific middleware function

Expand All @@ -547,23 +547,25 @@ These functions take an `options` object as a parameter. Some supported fields o
```js
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { ApolloServerPluginDrainHttpServer } = require('apollo-server-core');
const { typeDefs, resolvers } = require('./schema');

async function startApolloServer() {
const app = express();
const httpServer = http.createServer(app);
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();

const app = express();

// Additional middleware can be mounted at this point to run before Apollo.
app.use('*', jwtCheck, requireAuth, checkScope);

// Mount Apollo middleware here.
server.applyMiddleware({ app, path: '/specialUrl' });
await new Promise(resolve => app.listen({ port: 4000 }, resolve));
await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
return { server, app };
}
Expand Down
88 changes: 88 additions & 0 deletions docs/source/api/plugin/drain-http-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
title: "API Reference: Drain HTTP server plugin"
sidebar_title: Drain HTTP server
api_reference: true
---

## Using the plugin

This API reference documents the `ApolloServerPluginDrainHttpServer` plugin.

This plugin is designed for use with [`apollo-server-express` and other framework-specific packages](../../integrations/middleware/#all-supported-packages) which are built on top of [Node `http.Server`s](https://nodejs.org/api/http.html#http_class_http_server). It is highly recommended that you use this plugin with packages like `apollo-server-express` if you want your server to shut down gracefully.

You do not need to explicitly use this plugin with the batteries-included `apollo-server` package: that package automatically uses this plugin internally.

When you use this plugin, Apollo Server will drain your HTTP server when you call the `stop()` method (which is also called for you when the `SIGTERM` and `SIGINT` signals are received, unless disabled with the [`stopOnTerminationSignals` constructor option](./apollo-server/#stoponterminationsignals)). Specifically, it will:

* Stop listening for new connections
* Close idle connections (i.e., connections with no current HTTP request)
* Close active connections whenever they become idle
* Wait for all connections to be closed
* After a grace period, if any connections remain active, forcefully close them.

This plugin is exported from the `apollo-server-core` package. It is tested with `apollo-server-express`, `apollo-server-koa`, and `apollo-server-fastify`. (If you're using Hapi, you should instead use the `ApolloServerPluginStopHapiServer` plugin exported from the `apollo-server-hapi` package.)

```js
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { ApolloServerPluginDrainHttpServer } = require('apollo-server-core');
const { typeDefs, resolvers } = require('./schema');

async function startApolloServer() {
const app = express();
const httpServer = http.createServer(app);
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();

// Mount Apollo middleware here.
server.applyMiddleware({ app });
await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
return { server, app };
}
```

## Options

<table class="field-table">
<thead>
<tr>
<th>Name /<br/>Type</th>
<th>Description</th>
</tr>
</thead>

<tbody>

<tr>
<td>

###### `httpServer`

[`http.Server`](https://nodejs.org/api/http.html#http_class_http_server)
</td>
<td>

The server to drain; required.
</td>
</tr>

<tr>
<td>

###### `stopGracePeriodMillis`

`number`
</td>
<td>

How long to wait before forcefully closing non-idle connections. Defaults to `10_000` (ten seconds).
</td>
</tr>

</tbody>
</table>
41 changes: 30 additions & 11 deletions docs/source/data/subscriptions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,26 @@ To run both an Express app _and_ a separate subscription server, we'll create an
// This `server` is the instance returned from `new ApolloServer`.
path: server.graphqlPath,
});
```

// Shut down in the case of interrupt and termination signals
// We expect to handle this more cleanly in the future. See (#5074)[https://github.com/apollographql/apollo-server/issues/5074] for reference.
['SIGINT', 'SIGTERM'].forEach(signal => {
process.on(signal, () => subscriptionServer.close());
});
6. Add a plugin to your `ApolloServer` constructor to close the `SubscriptionServer`.

```javascript:title=index.js-10
const server = new ApolloServer({
schema,
plugins: [{
async serverWillStart() {
return {
async drainServer() {
subscriptionServer.close();
}
};
}
}],
});
```

6. Finally, we need to adjust our existing `listen` call.
7. Finally, we need to adjust our existing `listen` call.

Most Express applications call `app.listen(...)`. **Change this to `httpServer.listen(...)`** with the same arguments. This way, the server starts listening on the HTTP and WebSocket transports simultaneously.

Expand Down Expand Up @@ -136,17 +146,26 @@ import typeDefs from "./typeDefs";
resolvers,
});

const subscriptionServer = SubscriptionServer.create(
{ schema, execute, subscribe },
{ server: httpServer, path: server.graphqlPath }
);

const server = new ApolloServer({
schema,
plugins: [{
async serverWillStart() {
return {
async drainServer() {
subscriptionServer.close();
}
};
}
}],
});
await server.start();
server.applyMiddleware({ app });

SubscriptionServer.create(
{ schema, execute, subscribe },
{ server: httpServer, path: server.graphqlPath }
);

const PORT = 4000;
httpServer.listen(PORT, () =>
console.log(`Server is now running on http://localhost:${PORT}/graphql`)
Expand Down
Loading

0 comments on commit 2c375f1

Please sign in to comment.