跨AWS Lambda函数调用共享数据库连接

时间:2017-08-16 05:35:12

标签: node.js mongodb amazon-web-services aws-lambda serverless

所以我按照这里的例子https://www.mongodb.com/blog/post/optimizing-aws-lambda-performance-with-mongodb-atlas-and-nodejs来优化我的lambda函数。

我尝试了两种方法,并使用serverless-offline在本地对它们进行了测试,但这两种方法似乎都不起作用。

第一种方法

// endpoint file

import {connectToDatabase} from "lib/dbUtils.js";

let cachedDb = null;

export function post(event, context, callback) {
  let response;
  context.callbackWaitsForEmptyEventLoop = false;
  connectToDatabase()
    .then(//do other stuff

// lib/dbUtils.js

export async function connectToDatabase() {
  if (cachedDb && cachedDb.serverConfig.isConnected()) {
    console.log(" using cached db instance");
    return cachedDb;
  }
  cachedDb = await mongoose.createConnection(
    process.env.DB_URL,
    async err => {
      if (err) {
        throw err;
      }
    }
  );
  return cachedDb;
}

第二种方法

global.cachedDb = null;

export function post(event, context, callback) {
  let response;
  context.callbackWaitsForEmptyEventLoop = false;
  connectToDatabase()
    .then(connection => createUser(event.body, connection))


// lib/dbUtils.js

export async function connectToDatabase() {
  // eslint-disable-next-line
  if (global.cachedDb && global.cachedDb.serverConfig.isConnected()) {
    // eslint-disable-next-line
    console.log(" using cached db instance");
    // eslint-disable-next-line
    return global.cachedDb;
  }
  // eslint-disable-next-line
  global.cachedDb = await mongoose.createConnection(
    process.env.DB_URL,
    async err => {
      if (err) {
        throw err;
      }
    }
  );
  // eslint-disable-next-line
  return global.cachedDb;
}

在这两种情况下,using cached db instance控制台日志都不会运行。

为什么这不起作用?这是因为无服务器离线?

1 个答案:

答案 0 :(得分:0)

答案很简单:serverless-offline不模拟整个AWS。 使用AWS控制台制作真实的Lambda

MongoDB Atlas guide还可以,但是也值得检查描述每个lambda中的context选项的官方AWS Lambda documentation

  

callbackWaitsForEmptyEventLoop –设置为false以便在执行回调时立即发送响应,而不是等待Node.js事件循环为空。如果为false,则任何未完成的事件将在下一次调用期间继续运行。

可以在真正的Lambda上运行代码,并在控制台上查看using cached db instance。由于MongoDB的JavaScript代码相当差,因此我在下面编写了自己的版本:

var MongoClient = require("mongodb").MongoClient

let db = null

var log = console.log.bind(console)

var print = function(object) {
    return JSON.stringify(object, null, 2)
}

// Use your own credentials (and better yet, put them in environment variables)
const password = `notactuallyapassword`
const uri = `mongodb+srv://lambdauser:${password}@fakedomain.mongodb.net/test?retryWrites=true`

exports.handler = function(event, context, callback) {
    log(`Calling MongoDB Atlas from AWS Lambda with event: ${print(event)}`)
    var document = JSON.parse(JSON.stringify(event))

    const databaseName = "myDatabase",
        collectionName = "documents"

    // See https://www.mongodb.com/blog/post/optimizing-aws-lambda-performance-with-mongodb-atlas-and-nodejs
    // and https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html#nodejs-prog-model-context-properties
    context.callbackWaitsForEmptyEventLoop = false

    return createDoc(databaseName, collectionName, document)
}

async function createDoc(databaseName, collectionName, document) {
    var isConnected = db && db.serverConfig.isConnected()
    if (isConnected) {
        log(`Already connected to database, warm start!`)
    } else {
        log(`Connecting to database (cold start)`)
        var client = await MongoClient.connect(uri)
        db = client.db(databaseName)
    }

    var result = await db.collection(collectionName).insertOne(document)
    log(`just created an entry into the ${collectionName} collection with id: ${result.insertedId}`)
    // Don't close the connection thanks to context.callbackWaitsForEmptyEventLoop = false - this will re-use the connection on the next called (if it can re-use the same Lambda container)
    return result
}

使用 Test 按钮在AWS Lambda控制台中运行两次以上的lambda。

  • 首次运行它会看到Connecting to database (cold start)

  • 第二次看到Already connected to database, warm start!

请参见下面的屏幕快照中的日志输出部分:

enter image description here