update graceful shutdown

This commit is contained in:
Hongbo Wu
2024-04-09 16:49:03 +08:00
parent f2f18eb12b
commit 5f239d2dcb
5 changed files with 46 additions and 31 deletions

View File

@ -28,6 +28,7 @@ import { SetClaimsRole } from './utils/dictionary'
import { logger } from './utils/logger'
import { ReadingProgressDataSource } from './datasources/reading_progress_data_source'
import { createPrometheusExporterPlugin } from '@bmatei/apollo-prometheus-exporter'
import { ApolloServerPlugin } from 'apollo-server-plugin-base'
const signToken = promisify(jwt.sign)
const pubsub = createPubSubClient()
@ -112,10 +113,20 @@ export function makeApolloServer(app: Express): ApolloServer {
},
})
// enforce usage limits for the API
const usageLimitPlugin = (): ApolloServerPlugin<RequestContext> => {
return {
async requestDidStart(contextValue) {
// get graphql query from the request
console.log(contextValue)
},
}
}
const apollo = new ApolloServer({
schema: schema,
context: contextFunc,
plugins: [promExporter],
plugins: [promExporter, usageLimitPlugin],
formatError: (err) => {
logger.info('server error', err)
Sentry.captureException(err)
@ -124,6 +135,7 @@ export function makeApolloServer(app: Express): ApolloServer {
},
introspection: env.dev.isLocal,
persistedQueries: false,
stopOnTerminationSignals: false, // we handle this ourselves
})
return apollo

View File

@ -304,8 +304,19 @@ const main = async () => {
const gracefulShutdown = async (signal: string) => {
console.log(`[queue-processor]: Received ${signal}, closing server...`)
await new Promise<void>((resolve) => {
server.close((err) => {
console.log('[queue-processor]: Express server closed')
if (err) {
console.log('[queue-processor]: error stopping server', { err })
}
resolve()
})
})
await worker.close()
await redisDataSource.shutdown()
await appDataSource.destroy()
process.exit(0)
}

View File

@ -47,11 +47,7 @@ import { apiLimiter, authLimiter } from './utils/rate_limit'
const PORT = process.env.PORT || 4000
export const createApp = (): {
app: Express
apollo: ApolloServer
httpServer: Server
} => {
export const createApp = (): Express => {
const app = express()
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -136,10 +132,7 @@ export const createApp = (): {
res.end(await prom.register.metrics())
})
const apollo = makeApolloServer(app)
const httpServer = createServer(app)
return { app, apollo, httpServer }
return app
}
const main = async (): Promise<void> => {
@ -154,19 +147,17 @@ const main = async (): Promise<void> => {
await redisDataSource.initialize()
}
const { app, apollo, httpServer } = createApp()
const app = createApp()
const apollo = makeApolloServer(app)
await apollo.start()
apollo.applyMiddleware({ app, path: '/api/graphql', cors: corsConfig })
if (!env.dev.isLocal) {
const mwLogger = loggers.get('express', { levels: config.syslog.levels })
const transport = buildLoggerTransport('express')
const mw = await lw.express.makeMiddleware(mwLogger, transport)
app.use(mw)
}
const mwLogger = loggers.get('express', { levels: config.syslog.levels })
const transport = buildLoggerTransport('express')
const mw = await lw.express.makeMiddleware(mwLogger, transport)
app.use(mw)
const listener = httpServer.listen({ port: PORT }, async () => {
const listener = app.listen({ port: PORT }, async () => {
const logger = buildLogger('app.dispatch')
logger.notice(`🚀 Server ready at ${apollo.graphqlPath}`)
})
@ -181,15 +172,14 @@ const main = async (): Promise<void> => {
listener.timeout = 640 * 1000 // match headersTimeout
const gracefulShutdown = async (signal: string) => {
console.log(`[api]: Received ${signal}, closing server...`)
await apollo.stop()
console.log('[api]: Apollo server stopped')
console.log('[posthog]: flushing events')
await analytics.shutdownAsync()
console.log('[posthog]: events flushed')
console.log(`[api]: Received ${signal}, closing server...`)
await apollo.stop()
console.log('[api]: Apollo server stopped')
await new Promise<void>((resolve) => {
listener.close((err) => {
console.log('[api]: Express listener closed')

View File

@ -7,16 +7,16 @@ export const mochaGlobalTeardown = async () => {
await stopApolloServer()
console.log('apollo server stopped')
await appDataSource.destroy()
console.log('db connection closed')
if (env.redis.cache.url) {
await redisDataSource.shutdown()
console.log('redis connection closed')
if (redisDataSource.workerRedisClient) {
await stopWorker()
console.log('worker closed')
}
await redisDataSource.shutdown()
console.log('redis connection closed')
}
await appDataSource.destroy()
console.log('db connection closed')
}

View File

@ -2,11 +2,13 @@ import { ConnectionOptions, Job, QueueEvents, Worker } from 'bullmq'
import { nanoid } from 'nanoid'
import supertest from 'supertest'
import { v4 } from 'uuid'
import { makeApolloServer } from '../src/apollo'
import { createWorker, QUEUE_NAME } from '../src/queue-processor'
import { createApp } from '../src/server'
import { corsConfig } from '../src/utils/corsConfig'
const { app, apollo } = createApp()
const app = createApp()
const apollo = makeApolloServer(app)
export const request = supertest(app)
let worker: Worker
let queueEvents: QueueEvents