From 15426d9859f0ba0dbdd0da52f6b85d5b2d2f7d30 Mon Sep 17 00:00:00 2001 From: David Glasser Date: Mon, 22 Mar 2021 14:14:41 -0700 Subject: [PATCH] bring back willStart --- CHANGELOG.md | 2 +- .../apollo-server-core/src/ApolloServer.ts | 37 +++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c27ab023c0..b9d4d30f067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ The version headers in this history reflect the versions of Apollo Server itself > The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. With few exceptions, the format of the entry should follow convention (i.e., prefix with package name, use markdown `backtick formatting` for package names and code, suffix with a link to the change-set à la `[PR #YYY](https://link/pull/YYY)`, etc.). When a release is being prepared, a new header will be (manually) created below and the appropriate changes within that release will be moved into the new section. -- Improve startup error handling by ensuring that your server has loaded its schema and executed its `serverWillStart` handlers successfully before starting an HTTP server. If you're using the `apollo-server` package, no code changes are necessary. If you're using an integration such as `apollo-server-express` that is not a "serverless framework", you can insert [`await server.start()`](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#start) between `server = new ApolloServer()` and `server.applyMiddleware`. (If you don't call `server.start()` yourself, your server will still work, but the previous behavior of starting a web server that may fail to load its schema still applies.) The serverless framework integrations (Lambda, Azure Functions, and Cloud Functions) do not support this functionality. The protected method `willStart` has been removed; `start` or the new protected method `ensureStarting` should fulfill the same purpose if you were using it. [PR #4981](https://github.com/apollographql/apollo-server/pull/4981) +- Improve startup error handling by ensuring that your server has loaded its schema and executed its `serverWillStart` handlers successfully before starting an HTTP server. If you're using the `apollo-server` package, no code changes are necessary. If you're using an integration such as `apollo-server-express` that is not a "serverless framework", you can insert [`await server.start()`](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#start) between `server = new ApolloServer()` and `server.applyMiddleware`. (If you don't call `server.start()` yourself, your server will still work, but the previous behavior of starting a web server that may fail to load its schema still applies.) The serverless framework integrations (Lambda, Azure Functions, and Cloud Functions) do not support this functionality. While the protected method `willStart` still exists for backwards compatibility, you should replace calls to it with `start` or the new protected method `ensureStarting`. [PR #4981](https://github.com/apollographql/apollo-server/pull/4981) ## v2.21.2 diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index a4872b086f1..cca871e342b 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -129,7 +129,7 @@ type ServerState = barrier: Resolvable; schemaDerivedData: SchemaDerivedData; } - | { phase: 'failed to start'; error: Error } + | { phase: 'failed to start'; error: Error; loadedSchema: boolean } | { phase: 'started'; schemaDerivedData: SchemaDerivedData; @@ -499,6 +499,8 @@ export class ApolloServerBase { return await this._start(); } + // This is protected so that it can be called from `apollo-server`. It is + // otherwise an internal implementation detail. protected async _start(): Promise { const initialState = this.state; if ( @@ -511,6 +513,7 @@ export class ApolloServerBase { } const barrier = resolvable(); this.state = { phase: 'starting', barrier }; + let loadedSchema = false; try { const schemaDerivedData = initialState.phase === 'initialized with schema' @@ -518,7 +521,7 @@ export class ApolloServerBase { : this.generateSchemaDerivedData( await this.startGatewayAndLoadSchema(initialState.gateway), ); - + loadedSchema = true; this.state = { phase: 'invoking serverWillStart', barrier, @@ -571,13 +574,39 @@ export class ApolloServerBase { this.state = { phase: 'started', schemaDerivedData }; } catch (error) { - this.state = { phase: 'failed to start', error }; + this.state = { phase: 'failed to start', error, loadedSchema }; throw error; } finally { barrier.resolve(); } } + /** + * @deprecated This deprecated method is provided for backwards compatibility + * with the pre-v2.22 API. It could be used for purposes similar to `start` or + * `ensureStarting`, and was used by integrations. It had odd error handling + * semantics, in that it would ignore any error that came from loading the + * schema, but would throw errors that came from `serverWillStart`. Anyone + * calling it should call `start` or `ensureStarting` instead. + */ + protected async willStart() { + try { + this._start(); + } catch (e) { + if ( + this.state.phase === 'failed to start' && + this.state.error === e && + !this.state.loadedSchema + ) { + // For backwards compatibility with the odd semantics of the old + // willStart method, don't throw if the error occurred in loading the + // schema. + return; + } + throw e; + } + } + // Part of the backwards-compatibility behavior described above `start` to // make ApolloServer work if you don't explicitly call `start`, as well as for // serverless frameworks where there is no `start`. This is called at the @@ -594,7 +623,7 @@ export class ApolloServerBase { switch (this.state.phase) { case 'initialized with gateway': case 'initialized with schema': - await this.start(); + await this._start(); // continue the while loop break; case 'starting':