«Время ожидания задачи истекло после …» при подключении к базе данных MongoDB с помощью функции AWS Lambda

#mongodb #amazon-web-services #aws-lambda

#mongodb #amazon-web-services #aws-lambda

Вопрос:

У меня есть Node.js сценарий, в начале которого я подключаюсь к своей базе данных MongoDB, получаю определенную коллекцию и использую ее в скрипте. Я установил этот скрипт в функции AWS Lambda с таймаутом 10 секунд. Когда я тестирую AWS Lambda с помощью настроенного тестового события, я получаю сообщение «Время ожидания задачи истекло через 10.00 секунд». Предполагается, что мой скрипт по-прежнему будет запускаться после его подключения и завершения остальной части скрипта. Однако он останавливается, и я получаю сообщение об ошибке тайм-аута от AWS Lambda. Если я устанавливаю время ожидания выше, например, 15 минут, я получаю ошибку тайм-аута через 15 минут после подключения к базе данных MongoDB в скрипте (я понял это, просматривая журналы CloudWatch для функции AWS Lambda). Я экспериментировал с разными таймингами тайм-аута и обнаружил, что в течение x секунд, которые я устанавливаю для тайм-аута, мой скрипт выдает ошибку тайм-аута через x секунд после подключения к базе данных MongoDB. Я следовал всем рекомендациям, упомянутым в этой статье о подключении к MongoDB из AWS Lambda, и они следующие: определение клиентского соединения MongoDB вне функции обработчика и установка свойства context callbackWaitsForEmptyEventLoop на false . Я не уверен, как это исправить. Ниже приведен некоторый соответствующий код, который я использовал в своем скрипте:

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 amp;amp; 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
}
 

Другая информация: я использую serverless для отправки скрипта в AWS Lambda, а также использую бессерверный плагин «serverless-webpack» для файлов TypeScript.

Комментарии:

1. Ваш лямбда-код в VPC?

2. @Marcin Нет, это не в VPC.

3. Вызовите callback или удалите его.

4. @hoangdv Я удалил параметр обратного вызова, и происходит то же самое. Я не знаю, как вызвать callback , т.е. куда я должен позвонить в коде и что я должен передать ему?

5. @hoangdv Также моя функция-обработчик async , поэтому я думаю, что мне это не понадобится callback .

Ответ №1:

В рекомендации, приведенной в вашей статье, говорится Define the MongoDB client connection outside of your handler function . В вашем случае вам следует изменить const db = ... db = ... и объявить db вне вашей функции-обработчика и изменить ее на let db = null like в примере в статье, чтобы вы могли повторно использовать соединения в разных вызовах Lambda. Например:

 let db = null;

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

  // do something with your db

  callback();
};
 

Кроме того, воспользуйтесь советом @hoangdv и вызовите callback функцию, чтобы сообщить AWS Lambda, что вы закончили обработку события. Это должно сработать.

Комментарии:

1. Я попробовал это, где я определяю db переменную непосредственно вне handler функции, но получаю ту же ошибку тайм-аута. Я также пробовал это с помощью вызова callback() после подключения к базе данных, однако код просто останавливается при обратном вызове с null ответом.

Ответ №2:

Я обнаружил, что функции AWS Lambda могут выполняться не более 15 минут (даже если код все еще выполняется по истечении этого промежутка времени). Если бы я хотел запускать скрипт более 15 минут, я думаю, мне пришлось бы использовать экземпляр AWS EC2.

Источник: https://aws.amazon.com/lambda/faqs /