-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
draft: async server.start() function
Full description to come, but tl;dr: Previously server startup worked like this: - AS constructor runs - If no gateway, calculate schema and schema derived data immediately - If gateway, kick off gateway.load from the end of the constructor, and if it async-throws, log an error once and make the server kinda broken forever - At various spots in the framework integration code, call (but not await) protected willStart, which is an async function that first waits for the gateway to load the schema if necessary and then runs serverWillStart plugin functions; save the Promise returned by calling this. - At request time in the framework integration code, await that promise. And also if there's no schema fail with an error. Now server startup works like this: - There's an explicit state machine situation inside AS - AS constructor initializes state with schema directly if no gateway - If there is a gateway the constructor DOES NOT KICK OFF gateway.load - You can now call `await server.start()` yourself, which will first await gateway.load if necessary, and then await all serverWillStart calls - If you're using `apollo-server` rather than an integration, `server.listen()` will just transparently do this for you; explicit `start()` is just for integrations - The integration places that used to call willStart now call `server.ensureStarting()` instead which will kick off server.start in the background if you didn't (and log any errors thrown). - The places that used to await promiseWillStart no longer do so; generally right after that code we end up calling graphqlServerOptions - graphqlServerOptions now awaits `server.ensureStarted` which will start the server if necessary and throw if it threw. Overall changes: - If you're using `apollo-server`, startup errors will cause `listen` to reject, nothing else necessary. - If you're using an integration you are encouraged to call `await server.start()` yourself after the constructor, which will let you detect startup errors. - But if you don't do that, the server will still start up with similar properties. gateway.load won't start until the integration's `ensureStarting` or graphqlServerOptions' `ensuresStarted` though. Errors will be logged. - Also if you don't call `server.start()`, the full stack trace of any startup error will be logged on *every* failed graphql request instead of just a short message suggesting there's more in logs (but it's only at the beginning of your logs) Yes this is the tl;dr version that I jotted off at the end of my work day off the top of my head without going back and skimming through the PR for details :) Fixes #4921. Fixes apollographql/federation#335.
- Loading branch information
Showing
27 changed files
with
641 additions
and
473 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 43 additions & 28 deletions
71
packages/apollo-server-cache-redis/src/__mocks__/ioredis.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,53 @@ | ||
const IORedis = jest.genMockFromModule('ioredis'); | ||
class Redis { | ||
private keyValue = {}; | ||
private timeouts = new Set<NodeJS.Timer>(); | ||
|
||
const keyValue = {}; | ||
async del(key: string) { | ||
delete this.keyValue[key]; | ||
return true; | ||
} | ||
|
||
const deleteKey = key => { | ||
delete keyValue[key]; | ||
return Promise.resolve(true); | ||
}; | ||
async get(key: string) { | ||
if (this.keyValue[key]) { | ||
return this.keyValue[key].value; | ||
} | ||
} | ||
|
||
const getKey = key => { | ||
if (keyValue[key]) { | ||
return Promise.resolve(keyValue[key].value); | ||
async mget(...keys: string[]) { | ||
return keys.map((key) => { | ||
if (this.keyValue[key]) { | ||
return this.keyValue[key].value; | ||
} | ||
}); | ||
} | ||
|
||
return Promise.resolve(undefined); | ||
}; | ||
async set(key, value, type, ttl) { | ||
this.keyValue[key] = { | ||
value, | ||
ttl, | ||
}; | ||
if (ttl) { | ||
const timeout = setTimeout(() => { | ||
this.timeouts.delete(timeout); | ||
delete this.keyValue[key]; | ||
}, ttl * 1000); | ||
this.timeouts.add(timeout); | ||
} | ||
return true; | ||
} | ||
|
||
nodes() { | ||
return []; | ||
} | ||
|
||
const mGetKey = (key, cb) => getKey(key).then(val => [val]); | ||
async flushdb() {} | ||
|
||
const setKey = (key, value, type, ttl) => { | ||
keyValue[key] = { | ||
value, | ||
ttl, | ||
}; | ||
if (ttl) { | ||
setTimeout(() => { | ||
delete keyValue[key]; | ||
}, ttl * 1000); | ||
async quit() { | ||
this.timeouts.forEach((t) => clearTimeout(t)); | ||
} | ||
return Promise.resolve(true); | ||
}; | ||
} | ||
|
||
IORedis.prototype.del.mockImplementation(deleteKey); | ||
IORedis.prototype.get.mockImplementation(getKey); | ||
IORedis.prototype.mget.mockImplementation(mGetKey); | ||
IORedis.prototype.set.mockImplementation(setKey); | ||
// Use the same mock as Redis.Cluster. | ||
(Redis as any).Cluster = Redis; | ||
|
||
export default IORedis; | ||
export default Redis; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.