Add GQL requests caching in eden-watcher (#234)

This commit is contained in:
prathamesh0 2022-11-16 08:31:18 -06:00 committed by GitHub
parent 74741184ee
commit 1ad223db4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 190 additions and 26 deletions

View File

@ -28,6 +28,17 @@
# Interval in number of blocks at which to clear entities cache. # Interval in number of blocks at which to clear entities cache.
clearEntitiesCacheInterval = 1000 clearEntitiesCacheInterval = 1000
# GQL cache settings
[server.gqlCache]
enabled = true
# Max in-memory cache size (in bytes) (default 8 MB)
# maxCacheSize
# GQL cache-control max-age settings (in seconds)
maxAge = 15
timeTravelMaxAge = 86400 # 1 day
[metrics] [metrics]
host = "127.0.0.1" host = "127.0.0.1"
port = 9000 port = 9000

View File

@ -8,7 +8,7 @@ import debug from 'debug';
import Decimal from 'decimal.js'; import Decimal from 'decimal.js';
import { GraphQLResolveInfo, GraphQLScalarType } from 'graphql'; import { GraphQLResolveInfo, GraphQLScalarType } from 'graphql';
import { BlockHeight, OrderDirection, gqlTotalQueryCount, gqlQueryCount, jsonBigIntStringReplacer, getResultState } from '@cerc-io/util'; import { BlockHeight, OrderDirection, gqlTotalQueryCount, gqlQueryCount, jsonBigIntStringReplacer, getResultState, setGQLCacheHints } from '@cerc-io/util';
import { Indexer } from './indexer'; import { Indexer } from './indexer';
import { EventWatcher } from './events'; import { EventWatcher } from './events';
@ -37,6 +37,8 @@ const log = debug('vulcanize:resolver');
export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatcher): Promise<any> => { export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatcher): Promise<any> => {
assert(indexer); assert(indexer);
const gqlCacheConfig = indexer.serverConfig.gqlCache;
return { return {
BigInt: new BigInt('bigInt'), BigInt: new BigInt('bigInt'),
@ -88,6 +90,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('producer').inc(1); gqlQueryCount.labels('producer').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Producer, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Producer, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -102,6 +107,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('producers').inc(1); gqlQueryCount.labels('producers').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntities( return indexer.getSubgraphEntities(
Producer, Producer,
block, block,
@ -122,6 +130,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('producerSet').inc(1); gqlQueryCount.labels('producerSet').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(ProducerSet, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(ProducerSet, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -136,6 +147,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('producerSetChange').inc(1); gqlQueryCount.labels('producerSetChange').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(ProducerSetChange, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(ProducerSetChange, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -150,6 +164,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('producerRewardCollectorChange').inc(1); gqlQueryCount.labels('producerRewardCollectorChange').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(ProducerRewardCollectorChange, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(ProducerRewardCollectorChange, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -164,6 +181,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('rewardScheduleEntry').inc(1); gqlQueryCount.labels('rewardScheduleEntry').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(RewardScheduleEntry, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(RewardScheduleEntry, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -178,6 +198,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('rewardSchedule').inc(1); gqlQueryCount.labels('rewardSchedule').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(RewardSchedule, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(RewardSchedule, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -192,6 +215,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('producerEpoch').inc(1); gqlQueryCount.labels('producerEpoch').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(ProducerEpoch, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(ProducerEpoch, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -206,6 +232,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('block').inc(1); gqlQueryCount.labels('block').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Block, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Block, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -220,6 +249,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('blocks').inc(1); gqlQueryCount.labels('blocks').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntities( return indexer.getSubgraphEntities(
Block, Block,
block, block,
@ -240,6 +272,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('epoch').inc(1); gqlQueryCount.labels('epoch').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Epoch, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Epoch, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -254,6 +289,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('epoches').inc(1); gqlQueryCount.labels('epoches').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntities( return indexer.getSubgraphEntities(
Epoch, Epoch,
block, block,
@ -274,6 +312,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('slotClaim').inc(1); gqlQueryCount.labels('slotClaim').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(SlotClaim, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(SlotClaim, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -288,6 +329,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('slot').inc(1); gqlQueryCount.labels('slot').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Slot, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Slot, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -302,6 +346,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('staker').inc(1); gqlQueryCount.labels('staker').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Staker, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Staker, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -316,6 +363,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('stakers').inc(1); gqlQueryCount.labels('stakers').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntities( return indexer.getSubgraphEntities(
Staker, Staker,
block, block,
@ -336,6 +386,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('network').inc(1); gqlQueryCount.labels('network').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Network, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Network, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -364,6 +417,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('distribution').inc(1); gqlQueryCount.labels('distribution').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Distribution, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Distribution, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -378,6 +434,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('claim').inc(1); gqlQueryCount.labels('claim').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Claim, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Claim, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -392,6 +451,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('slash').inc(1); gqlQueryCount.labels('slash').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Slash, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Slash, id, block, info.fieldNodes[0].selectionSet.selections);
}, },
@ -406,6 +468,9 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch
gqlQueryCount.labels('account').inc(1); gqlQueryCount.labels('account').inc(1);
assert(info.fieldNodes[0].selectionSet); assert(info.fieldNodes[0].selectionSet);
// Set cache-control hints
setGQLCacheHints(info, block, gqlCacheConfig);
return indexer.getSubgraphEntity(Account, id, block, info.fieldNodes[0].selectionSet.selections); return indexer.getSubgraphEntity(Account, id, block, info.fieldNodes[0].selectionSet.selections);
}, },

View File

@ -1,3 +1,14 @@
enum CacheControlScope {
PUBLIC
PRIVATE
}
directive @cacheControl(
maxAge: Int
scope: CacheControlScope
inheritMaxAge: Boolean
) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
scalar BigInt scalar BigInt
scalar Bytes scalar Bytes
@ -264,14 +275,14 @@ type Producer {
type ProducerSet { type ProducerSet {
id: ID! id: ID!
producers: [Producer!]! producers: [Producer!]! @cacheControl(inheritMaxAge: true)
} }
type ProducerSetChange { type ProducerSetChange {
id: ID! id: ID!
blockNumber: BigInt! blockNumber: BigInt!
producer: Bytes! producer: Bytes!
changeType: ProducerSetChangeType! changeType: ProducerSetChangeType! @cacheControl(inheritMaxAge: true)
} }
enum ProducerSetChangeType { enum ProducerSetChangeType {
@ -295,10 +306,10 @@ type RewardScheduleEntry {
type RewardSchedule { type RewardSchedule {
id: ID! id: ID!
rewardScheduleEntries: [RewardScheduleEntry!]! rewardScheduleEntries: [RewardScheduleEntry!]! @cacheControl(inheritMaxAge: true)
lastEpoch: Epoch lastEpoch: Epoch @cacheControl(inheritMaxAge: true)
pendingEpoch: Epoch pendingEpoch: Epoch @cacheControl(inheritMaxAge: true)
activeRewardScheduleEntry: RewardScheduleEntry activeRewardScheduleEntry: RewardScheduleEntry @cacheControl(inheritMaxAge: true)
} }
type Block { type Block {
@ -336,12 +347,12 @@ type Epoch {
id: ID! id: ID!
finalized: Boolean! finalized: Boolean!
epochNumber: BigInt! epochNumber: BigInt!
startBlock: Block startBlock: Block @cacheControl(inheritMaxAge: true)
endBlock: Block endBlock: Block @cacheControl(inheritMaxAge: true)
producerBlocks: BigInt! producerBlocks: BigInt!
allBlocks: BigInt! allBlocks: BigInt!
producerBlocksRatio: BigDecimal! producerBlocksRatio: BigDecimal!
producerRewards: [ProducerEpoch!]! producerRewards: [ProducerEpoch!]! @cacheControl(inheritMaxAge: true)
} }
input Epoch_filter { input Epoch_filter {
@ -352,7 +363,7 @@ input Epoch_filter {
type ProducerEpoch { type ProducerEpoch {
id: ID! id: ID!
address: Bytes! address: Bytes!
epoch: Epoch! epoch: Epoch! @cacheControl(inheritMaxAge: true)
totalRewards: BigInt! totalRewards: BigInt!
blocksProduced: BigInt! blocksProduced: BigInt!
blocksProducedRatio: BigDecimal! blocksProducedRatio: BigDecimal!
@ -360,7 +371,7 @@ type ProducerEpoch {
type SlotClaim { type SlotClaim {
id: ID! id: ID!
slot: Slot! slot: Slot! @cacheControl(inheritMaxAge: true)
owner: Bytes! owner: Bytes!
winningBid: BigInt! winningBid: BigInt!
oldBid: BigInt! oldBid: BigInt!
@ -378,7 +389,7 @@ type Slot {
startTime: BigInt! startTime: BigInt!
expirationTime: BigInt! expirationTime: BigInt!
taxRatePerDay: BigDecimal! taxRatePerDay: BigDecimal!
claims: [SlotClaim!]! claims: [SlotClaim!]! @cacheControl(inheritMaxAge: true)
} }
type Staker { type Staker {
@ -397,10 +408,10 @@ enum Staker_orderBy {
type Network { type Network {
id: ID! id: ID!
slot0: Slot slot0: Slot @cacheControl(inheritMaxAge: true)
slot1: Slot slot1: Slot @cacheControl(inheritMaxAge: true)
slot2: Slot slot2: Slot @cacheControl(inheritMaxAge: true)
stakers: [Staker!]! stakers: [Staker!]! @cacheControl(inheritMaxAge: true)
numStakers: BigInt numStakers: BigInt
totalStaked: BigInt! totalStaked: BigInt!
stakedPercentiles: [BigInt!]! stakedPercentiles: [BigInt!]!
@ -408,12 +419,12 @@ type Network {
type Distributor { type Distributor {
id: ID! id: ID!
currentDistribution: Distribution currentDistribution: Distribution @cacheControl(inheritMaxAge: true)
} }
type Distribution { type Distribution {
id: ID! id: ID!
distributor: Distributor! distributor: Distributor! @cacheControl(inheritMaxAge: true)
timestamp: BigInt! timestamp: BigInt!
distributionNumber: BigInt! distributionNumber: BigInt!
merkleRoot: Bytes! merkleRoot: Bytes!
@ -424,7 +435,7 @@ type Claim {
id: ID! id: ID!
timestamp: BigInt! timestamp: BigInt!
index: BigInt! index: BigInt!
account: Account! account: Account! @cacheControl(inheritMaxAge: true)
totalEarned: BigInt! totalEarned: BigInt!
claimed: BigInt! claimed: BigInt!
} }
@ -433,14 +444,14 @@ type Account {
id: ID! id: ID!
totalClaimed: BigInt! totalClaimed: BigInt!
totalSlashed: BigInt! totalSlashed: BigInt!
claims: [Claim!]! claims: [Claim!]! @cacheControl(inheritMaxAge: true)
slashes: [Slash!]! slashes: [Slash!]! @cacheControl(inheritMaxAge: true)
} }
type Slash { type Slash {
id: ID! id: ID!
timestamp: BigInt! timestamp: BigInt!
account: Account! account: Account! @cacheControl(inheritMaxAge: true)
slashed: BigInt! slashed: BigInt!
} }

View File

@ -13,7 +13,7 @@ import { hideBin } from 'yargs/helpers';
import debug from 'debug'; import debug from 'debug';
import 'graphql-import-node'; import 'graphql-import-node';
import { DEFAULT_CONFIG_PATH, getConfig, Config, JobQueue, KIND_ACTIVE, initClients, startGQLMetricsServer, createAndStartServer } from '@cerc-io/util'; import { DEFAULT_CONFIG_PATH, getConfig, Config, JobQueue, KIND_ACTIVE, initClients, startGQLMetricsServer, createAndStartServerWithCache } from '@cerc-io/util';
import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node'; import { GraphWatcher, Database as GraphDatabase } from '@cerc-io/graph-node';
import { createResolvers } from './resolvers'; import { createResolvers } from './resolvers';
@ -37,7 +37,7 @@ export const main = async (): Promise<any> => {
const config: Config = await getConfig(argv.f); const config: Config = await getConfig(argv.f);
const { ethClient, ethProvider } = await initClients(config); const { ethClient, ethProvider } = await initClients(config);
const { host, port, kind: watcherKind } = config.server; const { kind: watcherKind } = config.server;
const db = new Database(config.database); const db = new Database(config.database);
await db.init(); await db.init();
@ -79,7 +79,7 @@ export const main = async (): Promise<any> => {
// Create an Express app // Create an Express app
const app: Application = express(); const app: Application = express();
const server = createAndStartServer(app, typeDefs, resolvers, { host, port }); const server = createAndStartServerWithCache(app, typeDefs, resolvers, config.server);
startGQLMetricsServer(config); startGQLMetricsServer(config);

View File

@ -4,11 +4,13 @@
"main": "dist/index.js", "main": "dist/index.js",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@apollo/utils.keyvaluecache": "^1.0.1",
"@cerc-io/solidity-mapper": "^0.2.13", "@cerc-io/solidity-mapper": "^0.2.13",
"@graphql-tools/schema": "^9.0.10", "@graphql-tools/schema": "^9.0.10",
"@graphql-tools/utils": "^9.1.1", "@graphql-tools/utils": "^9.1.1",
"apollo-server-core": "^3.11.1", "apollo-server-core": "^3.11.1",
"apollo-server-express": "^3.11.1", "apollo-server-express": "^3.11.1",
"apollo-server-plugin-response-cache": "^3.8.1",
"debug": "^4.3.1", "debug": "^4.3.1",
"decimal.js": "^10.3.1", "decimal.js": "^10.3.1",
"ethers": "^5.4.4", "ethers": "^5.4.4",

View File

@ -5,12 +5,78 @@ import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws'; import { useServer } from 'graphql-ws/lib/use/ws';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core'; import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import debug from 'debug'; import debug from 'debug';
import responseCachePlugin from 'apollo-server-plugin-response-cache';
import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache';
import { TypeSource } from '@graphql-tools/utils'; import { TypeSource } from '@graphql-tools/utils';
import { makeExecutableSchema } from '@graphql-tools/schema'; import { makeExecutableSchema } from '@graphql-tools/schema';
import { DEFAULT_MAX_GQL_CACHE_SIZE } from './constants';
import { ServerConfig } from './config';
const log = debug('vulcanize:server'); const log = debug('vulcanize:server');
export const createAndStartServerWithCache = async (
app: Application,
typeDefs: TypeSource,
resolvers: any,
serverConfig: ServerConfig
): Promise<ApolloServer> => {
const host = serverConfig.host;
const port = serverConfig.port;
const gqlCacheConfig = serverConfig.gqlCache;
// Create HTTP server
const httpServer = createServer(app);
// Create the schema
const schema = makeExecutableSchema({ typeDefs, resolvers });
// Create our WebSocket server using the HTTP server we just set up.
const wsServer = new WebSocketServer({
server: httpServer,
path: '/graphql'
});
const serverCleanup = useServer({ schema }, wsServer);
// Setup in-memory GQL cache
let gqlCache;
if (gqlCacheConfig && gqlCacheConfig.enabled) {
const maxSize = gqlCacheConfig.maxCacheSize ? gqlCacheConfig.maxCacheSize : DEFAULT_MAX_GQL_CACHE_SIZE;
gqlCache = new InMemoryLRUCache({ maxSize });
}
const server = new ApolloServer({
schema,
csrfPrevention: true,
cache: gqlCache,
plugins: [
// Proper shutdown for the HTTP server
ApolloServerPluginDrainHttpServer({ httpServer }),
// Proper shutdown for the WebSocket server
{
async serverWillStart () {
return {
async drainServer () {
await serverCleanup.dispose();
}
};
}
},
// GQL response cache plugin
responseCachePlugin()
]
});
await server.start();
server.applyMiddleware({ app });
httpServer.listen(port, host, () => {
log(`Server is listening on ${host}:${port}${server.graphqlPath}`);
});
return server;
};
export const createAndStartServer = async ( export const createAndStartServer = async (
app: Application, app: Application,
typeDefs: TypeSource, typeDefs: TypeSource,

View File

@ -3502,6 +3502,15 @@ apollo-server-plugin-base@^3.7.1:
dependencies: dependencies:
apollo-server-types "^3.7.1" apollo-server-types "^3.7.1"
apollo-server-plugin-response-cache@^3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/apollo-server-plugin-response-cache/-/apollo-server-plugin-response-cache-3.8.1.tgz#2d9559fe9951812dcda77fc2658422028f060af8"
integrity sha512-c6bkrZjzX8Ac44CF7a4m9ans2QFV2C0XVUUDnuSWAX3G9ZWbs55NC+H3YtcFhAPoX7gv92RAu88ipMahd8NiUQ==
dependencies:
"@apollo/utils.keyvaluecache" "^1.0.1"
apollo-server-plugin-base "^3.7.1"
apollo-server-types "^3.7.1"
apollo-server-types@^3.7.1: apollo-server-types@^3.7.1:
version "3.7.1" version "3.7.1"
resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-3.7.1.tgz#87adfcb52ec0893999a9cfafd5474bfda7ab0798" resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-3.7.1.tgz#87adfcb52ec0893999a9cfafd5474bfda7ab0798"