Docs Menu
Docs Home
/
MongoDB Atlas
/

Manage Connections with AWS Lambda

On this page

  • Best Practices
  • Connection Example
  • AWS IAM Authentication
  • Other Authentication
  • AWS IAM Authentication
  • Other Authentication
  • AWS IAM Authentication
  • Other Authentication
  • AWS IAM Authentication
  • Other Authentication

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. When you define a new MongoClient, you should:

    1. Create the MongoClient object once.

    2. 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 you have a Lambda function that connects to a sharded cluster with many shards, you might experience performance issues. For example, with a ten shard cluster, the driver connects to all thirty mongos instances by default. You can use the srvMaxHosts option in your connection string to set the maximum number of hosts that the driver connects to. To improve driver performance, set srvMaxHosts=3. For example:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    To learn more, see Connection Options.

  • If you have a Lambda function that connects to a sharded cluster with many shards, you might experience performance issues. For example, with a ten shard cluster, the driver connects to all thirty mongos instances by default. You can use the srvMaxHosts option in your connection string to set the maximum number of hosts that the driver connects to. To improve driver performance, set srvMaxHosts=3. For example:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    To learn more, see Connection Options.

  • If you have a Lambda function that connects to a sharded cluster with many shards, you might experience performance issues. For example, with a ten shard cluster, the driver connects to all thirty mongos instances by default. You can use the srvMaxHosts option in your connection string to set the maximum number of hosts that the driver connects to. To improve driver performance, set srvMaxHosts=3. For example:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    To learn more, see Connection Options.

  • 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.

  • If you have a Lambda function that connects to a sharded cluster with many shards, you might experience performance issues. For example, with a ten shard cluster, the driver connects to all thirty mongos instances by default. You can use the srvMaxHosts option in your connection string to set the maximum number of hosts that the driver connects to. To improve driver performance, set srvMaxHosts=3. For example:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    To learn more, see Connection Options.

  • If you have a Lambda function that connects to a sharded cluster with many shards, you might experience performance issues. For example, with a ten shard cluster, the driver connects to all thirty mongos instances by default. You can use the srvMaxHosts option in your connection string to set the maximum number of hosts that the driver connects to. To improve driver performance, set srvMaxHosts=3. For example:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    To learn more, see Tools for Connecting to MongoDB.

  • If you have a Lambda function that connects to a sharded cluster with many shards, you might experience performance issues. For example, with a ten shard cluster, the driver connects to all thirty mongos instances by default. You can use the srvMaxHosts option in your connection string to set the maximum number of hosts that the driver connects to. To improve driver performance, set srvMaxHosts=3. For example:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    To learn more, see URI options.

  • If you have a Lambda function that connects to a sharded cluster with many shards, you might experience performance issues. For example, with a ten shard cluster, the driver connects to all thirty mongos instances by default. You can use the srvMaxHosts option in your connection string to set the maximum number of hosts that the driver connects to. To improve driver performance, set srvMaxHosts=3. For example:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.mongodb.net/?retryWrites=true&w=majority&srvMaxHosts=3

    To learn more, see Connection Options.

  • 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 from your IP access list.

    If you don't use private networking, 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.

    Warning

    Adding 0.0.0.0/0 to your IP access list allows cluster access from anywhere in the public internet. Ensure that you're using strong credentials for all database users when allowing access from anywhere.

  • Set maxIdleTimeMS to 60000 to automatically close your connections after 1 minute of idle time. Tuning your maxIdleTimeMS can help reduce the occurrence of timeout errors from your serverless functions.

  • Set Up Unified AWS Access and use AWS IAM authentication where possible.

    You can connect to your Atlas clusters using AWS IAM roles instead of hardcoding your credentials in Lambda. Hardcoded credentials are viewable by anyone who accesses your AWS Lambda environment, which can pose a security risk. With AWS IAM authentication, Atlas accesses AWS Lambda through an assumed IAM role, so you don't need credentials in your connection strings.

    Atlas supports AWS IAM authentication for clusters running MongoDB version 5.0 or higher. We strongly advise using AWS IAM authentication for Lambda connections if your cluster meets the requirements.

  • The amount of memory allocated to a Lambda function defaults to 128 MB. You can configure the amount of memory allocated to a Lambda function, between 128 MB and 10,240 MB. Ensure you allocate enough memory. Increase the memory to increase the amount of virtual CPU available and improve MongoDB driver performance. To learn more, see Memory and computing power.

  • Set your AWS_STS_REGIONAL_ENDPOINTS and AWS_REGION environment variables.

string username = Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID");
string password = Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY");
string awsSessionToken = Environment.GetEnvironmentVariable("AWS_SESSION_TOKEN");
var awsCredentials =
new MongoCredential("MONGODB-AWS", new MongoExternalIdentity(username), new PasswordEvidence(password))
.WithMechanismProperty("AWS_SESSION_TOKEN", awsSessionToken);
var mongoUrl = MongoUrl.Create($"<MONGODB_URI>");
var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl);
mongoClientSettings.Credential = awsCredentials;
mongoClientSettings.ServerApi = new ServerApi(ServerApiVersion.V1, strict: true);
return new MongoClient(mongoClientSettings);
private static MongoClient MongoClient { get; set; }
private static MongoClient CreateMongoClient()
{
var mongoClientSettings = MongoClientSettings.FromConnectionString($"<MONGODB_URI>");
mongoClientSettings.ServerApi = new ServerApi(ServerApiVersion.V1, strict: true);
return new MongoClient(mongoClientSettings);
}
static ShareMongoClientLambdaHandler()
{
MongoClient = CreateMongoClient();
}
public string HandleRequest(ILambdaContext context)
{
var database = MongoClient.GetDatabase("db");
var collection = database.GetCollection<BsonDocument>("coll");
var result = collection.Find(FilterDefinition<BsonDocument>.Empty).First();
return result.ToString();
}
var client, err = mongo.Connect(context.TODO(), options.Client().ApplyURI(os.Getenv("MONGODB_URI")))
func HandleRequest(ctx context.Context) error {
if err != nil {
return err
}
return client.Ping(context.TODO(), nil)
}
public class ExampleAwsLambdaHandler implements RequestHandler<String, String> {
private final MongoClient client;
public ExampleAwsLambdaHandler() {
client = MongoClients.create(System.getenv("MONGODB_URI"));
}
@Override
public String handleRequest(final String input, final Context context) {
return client.getDatabase("admin").runCommand(new Document("ping", 1)).toJson();
}
}
const { MongoClient } = require('mongodb');
// Get the URI for the cluster then set AWS_ACCESS_KEY_ID as the username in the
// URI and AWS_SECRET_ACCESS_KEY as the password, then set the appropriate auth
// options. Note that MongoClient now auto-connects so no need to store the connect()
// promise anywhere and reference it.
const client = new MongoClient(process.env.MONGODB_URI, {
auth: {
username: process.env.AWS_ACCESS_KEY_ID,
password: process.env.AWS_SECRET_ACCESS_KEY
},
authSource: '$external',
authMechanism: 'MONGODB-AWS'
});
module.exports.handler = async function () {
const databases = await client.db('admin').command({ listDatabases: 1 });
return {
statusCode: 200,
databases: databases
};
};
const { MongoClient } = require('mongodb');
// MongoClient now auto-connects so no need to store the connect()
// promise anywhere and reference it.
const client = new MongoClient(process.env.MONGODB_URI);
module.exports.handler = async function () {
const databases = await client.db('admin').command({ listDatabases: 1 });
return {
statusCode: 200,
databases: databases
};
};
import os
from pymongo import MongoClient
client = MongoClient(host=os.environ["MONGODB_URI"])
def lambda_handler(event, context):
return client.db.command("ping")
# Require the driver library.
require "mongo"
# Create a Mongo::Client instance using AWS IAM authentication.
# CRITICAL: You must create the client instance outside the handler
# so that the client can be reused across function invocations.
client = Mongo::Client.new([ENV.fetch("MONGODB_HOST")],
auth_mech: :aws,
user: ENV.fetch("AWS_ACCESS_KEY_ID"),
password: ENV.fetch("AWS_SECRET_ACCESS_KEY"),
auth_mech_properties: {
aws_session_token: ENV.fetch("AWS_SESSION_TOKEN"),
},
database: ENV.fetch("MONGODB_DATABASE"))
def lambda_handler(event:, context:)
# Use the client to return the name of the configured database.
client.database.name
end
# Require the driver library.
require "mongo"
# Create a Mongo::Client instance.
# CRITICAL: You must create the client instance outside the handler
# so that the client can be reused across function invocations.
client = Mongo::Client.new(ENV.fetch("MONGODB_URI"))
def lambda_handler(event:, context:)
# Use the client to return the name of the configured database.
client.database.name
end
use lambda_runtime::{service_fn, LambdaEvent};
use mongodb::{
bson::doc,
options::{AuthMechanism, ClientOptions, Credential},
Client,
};
use serde_json::Value;
use tokio::sync::OnceCell;
// Initialize a global static MongoDB Client with AWS authentication. The following environment
// variables should also be set: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and, optionally,
// AWS_SESSION_TOKEN.
static MONGODB_CLIENT: OnceCell<Client> = OnceCell::const_new();
async fn get_mongodb_client() -> &'static Client {
MONGODB_CLIENT
.get_or_init(|| async {
let uri = std::env::var("MONGODB_URI")
.expect("MONGODB_URI must be set to the URI of the MongoDB deployment");
let mut options = ClientOptions::parse(&uri)
.await
.expect("Failed to parse options from URI");
let credential = Credential::builder()
.mechanism(AuthMechanism::MongoDbAws)
.build();
options.credential = Some(credential);
Client::with_options(options).expect("Failed to create MongoDB Client")
})
.await
}
// Runs a ping operation on the "db" database and returns the response.
async fn handler(_: LambdaEvent<Value>) -> Result<Value, lambda_runtime::Error> {
let client = get_mongodb_client().await;
let response = client
.database("db")
.run_command(doc! { "ping": 1 })
.await?;
let json = serde_json::to_value(response)?;
Ok(json)
}
#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
let service = service_fn(handler);
lambda_runtime::run(service).await?;
Ok(())
}
use lambda_runtime::{service_fn, LambdaEvent};
use mongodb::{bson::doc, Client};
use serde_json::Value;
use tokio::sync::OnceCell;
// Initialize a global static MongoDB Client.
static MONGODB_CLIENT: OnceCell<Client> = OnceCell::const_new();
async fn get_mongodb_client() -> &'static Client {
MONGODB_CLIENT
.get_or_init(|| async {
let uri = std::env::var("MONGODB_URI")
.expect("MONGODB_URI must be set to the URI of the MongoDB deployment");
Client::with_uri_str(uri)
.await
.expect("Failed to create MongoDB Client")
})
.await
}
// Runs a ping operation on the "db" database and returns the response.
async fn handler(_: LambdaEvent<Value>) -> Result<Value, lambda_runtime::Error> {
let client = get_mongodb_client().await;
let response = client
.database("db")
.run_command(doc! { "ping": 1 })
.await?;
let json = serde_json::to_value(response)?;
Ok(json)
}
#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
let service = service_fn(handler);
lambda_runtime::run(service).await?;
Ok(())
}

Back

Simulate Regional Outage