Skip to content

Commit

Permalink
db: reuse cached connection if available in global state, for serverl…
Browse files Browse the repository at this point in the history
…ess support.
  • Loading branch information
tmilar committed Jul 18, 2019
1 parent 7947a8a commit 46e4db6
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 25 deletions.
12 changes: 10 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,16 @@ function closeServer() {
})
}

let dbConnection = null

async function setup() {
await Promise.all([
db.connect()
.then(({connection: {name, host, port}}) => console.log(`db connection open: ${host}:${port}/${name}`)),
.then(connection => {
const {connection: {name, host, port}} = connection
console.log(`db connection open: ${host}:${port}/${name}`)
dbConnection = connection
}),
QuestionsService.setup(),
OrdersService.setup(),
Account.findAllCached()
Expand All @@ -100,7 +106,9 @@ async function setup() {

async function shutdown(code = 0) {
await closeServer()
await db.disconnect()
if (dbConnection) {
await db.disconnect(dbConnection)
}
process.exitCode = code
}

Expand Down
56 changes: 33 additions & 23 deletions config/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mongoose.Promise = require('bluebird')
const debugDbConnecting = require('debug')('db:connecting')
const {db: dbUrl} = require('.')

// Cache db connection so it can be reused
// Cache db connection so it can be reused, if kept in the global scope
let cachedDb = null

/**
Expand All @@ -13,57 +13,67 @@ let cachedDb = null
const connect = async () => {
// If the database connection is cached,
// use it instead of creating a new connection
if (cachedDb) {
return cachedDb
}

const {connection: {readyState}} = mongoose

if (readyState === 1) {
return mongoose
if (cachedDb && !_isConnected(cachedDb)) {
cachedDb = null
console.log('[mongoose] client discard')
}

if (readyState === 2) {
console.log('DB is already connecting, please wait.')
return mongoose
if (cachedDb) {
if (_isConnected(cachedDb)) {
console.log('[mongoose] client connected, quick return')
} else if (_isConnecting(cachedDb)) {
console.log('[mongoose] client is already connecting, please wait. quick return')
} else {
console.log(`[mongoose] client status is ${cachedDb.connection.readyState}`)
}
return cachedDb
}

let ret
let db
try {
ret = await mongoose.connect(dbUrl, {useNewUrlParser: true})
db = await mongoose.connect(dbUrl, {
useNewUrlParser: true,
/*
Buffering allows Mongoose to queue up operations if MongoDB
gets disconnected, and to send them upon reconnection.
With serverless, it is better to fail fast when not connected.
*/
bufferCommands: false,
bufferMaxEntries: 0
})
} catch (error) {
console.error('db connection error:', error.message)
console.error('[mongoose] db connection error:', error.message)
throw error
}

cachedDb = ret
cachedDb = db

return ret
return db
}

/**
* Explicitly close mongo db connection.
*
* @returns {Promise<void>} - exec promise
*/
const disconnect = () => {
return mongoose.disconnect()
const disconnect = (db = mongoose) => {
return db.disconnect()
}

/**
* @returns {boolean} true if connection.state is 'connected' (value 1)
* @private
*/
const _isConnected = function () {
return mongoose.connection.readyState === 1
const _isConnected = function ({connection: {readyState}} = mongoose) {
return readyState === 1
}

/**
* @returns {boolean} true if connection.state is 'connecting' (value 2).
* @private
*/
const _isConnecting = function () {
return mongoose.connection.readyState === 2
const _isConnecting = function ({connection: {readyState}} = mongoose) {
return readyState === 2
}

/**
Expand Down

0 comments on commit 46e4db6

Please sign in to comment.