Best Practices Connecting from AWS Lambda¶
On this page
Use the following best practices to properly manage connections between AWS Lambda and Atlas:
Define the client to the MongoDB server outside the AWS Lambda handler function.
Don't define a new MongoClient object each time you invoke your function. Doing so causes the driver to create a new database connection with each function call. This can be expensive and can result in your application exceeding database connection limits. As an alternative, do the following:
- Create the MongoClient object once.
- Store the object so your function can reuse the MongoClient across function invocations.
The Connection Example reuses existing database connections to speed up communication with the database and keep connection counts to the database at a reasonable level with respect to application traffic.
If your handler takes a callback as its last argument, set the
callbackWaitsForEmptyEventLoop
property on the AWS Lambda Context object to false.context.callbackWaitsForEmptyEventLoop = false; This allows a Lambda function to return its result to the caller without requiring that the MongoDB database connection be closed. Setting this property is not applicable for async handlers.
Restrict network access to your Atlas cluster.
Connect to your Atlas cluster over private networking using a Network Peering connection between your Atlas cluster and your AWS Lambda function, or, alternatively, a private endpoint, so that you can allow only private IP addresses to your IP access list.
If private networking is not an option, consider connecting to your Atlas cluster via a NAT gateway with a mapped Elastic IP address. Otherwise, you must allow all IP addresses (0.0.0.0/0) to access your service cluster.
Connection Examples¶
This section includes examples for two approaches:
- In the first Node.js example, the
index.js
file shows how to reuseMongoclient.connect
across function invocations. - In the second Node.js example, the
index.js
andmongodb-client.js
files show how to isolate the call toMongoClient.connect
into its own module so that the connections can be reused across functions. Use this approach if you package multiple logical functions together in a single Lambda handler function.
The following example shows the best practice of defining the
MongoClient.connect
function in your application's Node.js code
outside the handler so it can be reused across function invocations.
1 ;2 3 // Import the dependency. 4 const { MongoClient } = require('mongodb'); 5 6 // Create a module-scoped MongoClient promise. 7 // CRITICAL: You must call connect() outside the handler so that the client 8 // can be reused across function invocations. 9 let client = new MongoClient(process.env.MONGODB_URI, 10 { useNewUrlParser: true, useUnifiedTopology: true }); 11 const clientPromise = client.connect(); 12 13 // Handler 14 module.exports.handler = async function(event, context) { 15 16 // Get the MongoClient by calling await on the promise. 17 // Because this is a promise, it will only resolve once. 18 client = await clientPromise; 19 20 // Use the client to return the name of the connected database. 21 return client.db().databaseName; 22 }
Some serverless frameworks that run on top of Lambda allow for
multiple logical functions to be packaged together in a single
Lambda handler function. If your application runs multiple functions
within the same Lambda process, we recommend isolating the call to
the MongoClient.connect
function into its own module so that
the connections can be reused across functions.
In the following code examples:
mongo-client.js
organizes theMongoClient.connect
function into its own module (mongo-client).index.js
imports that module and uses it to connect.
1 ;2 3 // Import the dependency. 4 const { MongoClient } = require('mongodb'); 5 6 // Export a module-scoped MongoClient promise. By doing this in a separate 7 // module, the client can be shared across functions. 8 const client = new MongoClient(process.env.MONGODB_URI, 9 { useNewUrlParser: true, useUnifiedTopology: true }); 10 module.exports = client.connect();
1 ;2 3 // Import the dependency. 4 const clientPromise = require('./mongodb-client'); 5 6 // Handler 7 module.exports.handler = async function(event, context) { 8 9 // Get the MongoClient by calling await on the connection promise. Because 10 // this is a promise, it will only resolve once. 11 const client = await clientPromise; 12 13 // Use the connection to return the name of the connected database. 14 return client.db().databaseName; 15 }