fix: Prevent MongoDB client promise being cached (#66977)

### What?
Update to
[examples/with-mongodb](https://github.com/vercel/next.js/tree/canary/examples/with-mongodb)
to incorporate fix from the MongoDB team. This should prevent
intermittent serverless function timeouts due to cached promise.

### Why?

Vercel users reported intermittent 500 errors when connecting to their
MongoDB Atlas clusters in production environments.

Full bug report: [NODE-6179](https://jira.mongodb.org/browse/NODE-6179)

Related issues:
- [10671](https://github.com/vercel/vercel/issues/10671)
- [5708](https://github.com/orgs/vercel/discussions/5708)
- [4297](https://github.com/orgs/vercel/discussions/4297)

### How?

Solution by @baileympearson – thank you 🖤

[View
commit](c08bc96353)
in `mongodb-developer/nextjs-with-mongodb`

---

- [x] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
- [x] Make sure the linting passes by running `pnpm build && pnpm lint`.
[See linting
docs](https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md).
This commit is contained in:
Aldo Schumann 2024-06-18 17:47:07 +10:00 committed by GitHub
parent dc461512d3
commit 86dbcbea43
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 9 additions and 26 deletions

View file

@ -13,27 +13,24 @@ const options = {
}, },
}; };
let client; let client: MongoClient;
let clientPromise: Promise<MongoClient>;
if (process.env.NODE_ENV === "development") { if (process.env.NODE_ENV === "development") {
// In development mode, use a global variable so that the value // In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement). // is preserved across module reloads caused by HMR (Hot Module Replacement).
let globalWithMongo = global as typeof globalThis & { let globalWithMongo = global as typeof globalThis & {
_mongoClientPromise?: Promise<MongoClient>; _mongoClient?: MongoClient;
}; };
if (!globalWithMongo._mongoClientPromise) { if (!globalWithMongo._mongoClient) {
client = new MongoClient(uri, options); globalWithMongo._mongoClient = new MongoClient(uri, options);
globalWithMongo._mongoClientPromise = client.connect();
} }
clientPromise = globalWithMongo._mongoClientPromise; client = globalWithMongo._mongoClient;
} else { } else {
// In production mode, it's best to not use a global variable. // In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options); client = new MongoClient(uri, options);
clientPromise = client.connect();
} }
// Export a module-scoped MongoClient promise. By doing this in a // Export a module-scoped MongoClient. By doing this in a
// separate module, the client can be shared across functions. // separate module, the client can be shared across functions.
export default clientPromise; export default client;

View file

@ -1,5 +1,5 @@
import Head from "next/head"; import Head from "next/head";
import clientPromise from "../lib/mongodb"; import client from "../lib/mongodb";
import type { InferGetServerSidePropsType, GetServerSideProps } from "next"; import type { InferGetServerSidePropsType, GetServerSideProps } from "next";
type ConnectionStatus = { type ConnectionStatus = {
@ -10,16 +10,7 @@ export const getServerSideProps: GetServerSideProps<
ConnectionStatus ConnectionStatus
> = async () => { > = async () => {
try { try {
await clientPromise; await client.connect(); // `await client.connect()` will use the default database passed in the MONGODB_URI
// `await clientPromise` will use the default database passed in the MONGODB_URI
// However you can use another database (e.g. myDatabase) by replacing the `await clientPromise` with the following code:
//
// `const client = await clientPromise`
// `const db = client.db("myDatabase")`
//
// Then you can execute queries against your database like so:
// db.find({}) or any of the MongoDB Node Driver commands
return { return {
props: { isConnected: true }, props: { isConnected: true },
}; };

View file

@ -1,5 +0,0 @@
import { MongoClient } from "mongodb";
declare global {
var _mongoClientPromise: Promise<MongoClient>;
}