Skip to content

Commit

Permalink
Fix with-mongodb hot-reload issue and race condition (#17666)
Browse files Browse the repository at this point in the history
This PR fixes 2 issues with the mongodb example:

### 1. Fallable Caching Strategy

Calling `connectToDatabase()` multiple times before it's cached results in multiple connections being created. The latest one created was becoming the "cached" one and the others dissappear into the background.

This is now fixed by using **promise sharing** so that only one connection can ever be created.

### 2. Problematic Hot Reload

During development you can monitor your database connections and see that it continues to create more and more connections over time. Some users have reported their [databases reaching maximum connection limits](#12229).

This is resolved by using `global` to store the cached connection. It's not ideal but it is necessary.
  • Loading branch information
ashconnell committed Oct 17, 2020
1 parent f01deee commit 8204154
Showing 1 changed file with 29 additions and 21 deletions.
50 changes: 29 additions & 21 deletions examples/with-mongodb/util/mongodb.js
@@ -1,37 +1,45 @@
import { MongoClient } from 'mongodb'

let uri = process.env.MONGODB_URI
let dbName = process.env.MONGODB_DB
const { MONGODB_URI, MONGODB_DB } = process.env

let cachedClient = null
let cachedDb = null

if (!uri) {
if (!MONGODB_URI) {
throw new Error(
'Please define the MONGODB_URI environment variable inside .env.local'
)
}

if (!dbName) {
if (!MONGODB_DB) {
throw new Error(
'Please define the MONGODB_DB environment variable inside .env.local'
)
}

/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentiatlly
* during API Route usage.
*/
let cached = global.mongo
if (!cached) cached = global.mongo = {}

export async function connectToDatabase() {
if (cachedClient && cachedDb) {
return { client: cachedClient, db: cachedDb }
if (cached.conn) return cached.conn
if (!cached.promise) {
const conn = {}
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true,
}
cached.promise = MongoClient.connect(MONGODB_URI, opts)
.then((client) => {
conn.client = client
return client.db(MONGODB_DB)
})
.then((db) => {
conn.db = db
cached.conn = conn
})
}

const client = await MongoClient.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
})

const db = await client.db(dbName)

cachedClient = client
cachedDb = db

return { client, db }
await cached.promise
return cached.conn
}

0 comments on commit 8204154

Please sign in to comment.