简体   繁体   中英

“Task timed out after…” when connecting to a MongoDB database in an AWS Lambda function

I am have Node.js script where in the beginning of it I connect to my MongoDB database and get a specific collection and use that within the script. I set this script up in an AWS Lambda function with a timeout of 10 seconds. When I test the AWS Lambda with a configured test event, I get a "Task timed out after 10.00 seconds". My script is still suppose to run after it connects and finish the rest of the script. However, it stops and I get a timeout error from AWS Lambda. If I set a timeout higher, such as 15 minutes, I get the timeout error 15 minutes after I connect to the MongoDB database within the script (I got this my looking at the CloudWatch logs for the AWS Lambda function). I experimented with different timeout timings and found that for x seconds I set the timeout, my script will give the timeout error x seconds after I connect to the MongoDB database. I followed all best practices mentioned in this article about connecting to MongoDB from AWS Lambda and they are are: defining the MongoDB client connection outside the handler function and setting the context property callbackWaitsForEmptyEventLoop to false . I am not sure how to fix this. Below is some relevant code I used in my script:

main.ts :

import { connectToDatabase } from './mongodb'
import mongodb from 'mongodb'

export const handler = async (event: any, context: any, callback: any) => {
    context.callbackWaitsForEmptyEventLoop = false
    const db = await connectToDatabase().then((db: mongodb.Db) => db).catch(error => error)
    var collection: mongodb.Collection = db.collection("{collection-name}")
    // Rest of the script
}

mongodb.ts :

import mongodb, { MongoClient } from "mongodb"

let uri: undefined | string = process.env.MONGODB_URI
let dbName: undefined | string = process.env.MONGODB_DB

let cachedClient: null | mongodb.MongoClient = null
let cachedDb: null | mongodb.Db = null

export async function connectToDatabase() {
  if (cachedClient && cachedDb) {
    return cachedDb
  }

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

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

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

  const db = client.db(dbName)

  cachedClient = client
  cachedDb = db

  return db
}

Other info: I use serverless to push the script to AWS Lambda and also using serverless plugin "serverless-webpack" for TypeScript files.

The best practice linked in your article says Define the MongoDB client connection outside of your handler function . In your case you should change const db =... to db =... and declare db outside of your handler function and change it to let db = null like in the example in the article, so you can reuse the connections in different Lambda invocations. For example:

let db = null;

export const handler = async (event, context, callback) => {
  if (!db) {
    db = connectToDatabase();
  }

  // do something with your db

  callback();
};

Besides that, take @hoangdv 's advice and call the callback function to signal AWS Lambda that you're done with handling the event. That should do the trick.

I found that AWS Lambda functions can only run for a maximum of 15 minutes (even if the code is still running after that amount of time). If I wanted to run the script for more than 15 minutes, I guess I would have to use an AWS EC2 instance.

Source: https://aws.amazon.com/lambda/faqs/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM