无服务器函数中的数据库连接缓存代码仅执行一次

Posted

技术标签:

【中文标题】无服务器函数中的数据库连接缓存代码仅执行一次【英文标题】:DB connection caching code in serverless function executes only once 【发布时间】:2019-06-25 15:55:10 【问题描述】:

我有一个连接到 MongoDB 实例的 lambda 函数,并且正在添加一个连接池重用逻辑,以便当一个容器被 lambda 重用时,之前的连接被重用,而不是创建一个新的连接。

在我的database.ts 文件中,以前在代码中到处都使用了一个export const db = mongo.createConnection(..),它在每次函数调用时都创建了一个新连接。

现在,根据在线教程,我将实际连接变量存储在文件中的全局变量中,并将导出转换为检查上述连接对象是否不是null的函数,如果是则返回它无需创建新连接。如果确实是null,那么它会创建一个连接并将createConnection的结果赋给变量并返回。

当然,我需要将db 的所有用法转换为db(),因为它现在是一个函数。文件中添加的日志表明,在第一次调用之后,该连接确实被重复用于所有对 db 的后续调用。

然后,我将db 转换为 IIFE 并返回正常导出。我想,与其将所有用法都替换为函数调用,不如在文件中调用它然后导出它。

然而现在,发生的事情很奇怪。第一次调用显示正在创建一个新连接。 (=> Creating a new database connection) 在代码中。但是,在随后的调用中,不会打印任何日志语句。理想情况下,不应在控制台上打印 (=> Reusing an existing connection) 吗?我想由于第一个日志没有出现,连接仍然被重用,但是为什么会出现这种现象呢?

我知道这与模块的 required 或缓存方式以及 AWS Lambda 如何处理 JS 模块有关。任何进一步的见解都会有所帮助。

let connection: mongoose.Connection | null = null;
let isPreviousConnectionAvailable = false;

export const db = (() => 
  if (!isPreviousConnectionAvailable) 
    log.debug('=> Creating a new database connection.');
    connection = mongoose.createConnection(dbConnectionURL,  useNewUrlParser: true );
    isPreviousConnectionAvailable = true;
   else 
    log.debug('=> Reusing an existing database connection');
  

  return connection;
)();

【问题讨论】:

【参考方案1】:

不会打印日志。因为它在第一次被导入时被调用,然后当容器变热时您将访问相同的常量。这是预期的行为。

【讨论】:

可能值得注意的是,else 分支实际上永远不会被调用并且isPreviousConnectionAvailable 测试是不必要的,因为db 将在每个容器启动时分配一个连接,并且该函数将在容器的生命周期内永远不会再次调用。 同意。这意味着只需将 connection 声明为全局变量(在任何 lambda 函数之外)并设置 context.callbackWaitsForEmptyEventLoop = false 就足以利用数据库连接池重用。 @Michael-sqlbot @visheshd

以上是关于无服务器函数中的数据库连接缓存代码仅执行一次的主要内容,如果未能解决你的问题,请参考以下文章

MySQL存储过程

一次仅访问一个可执行文件以访问 .so 库中的函数

仅缓存 FuelPHP ORM 结果中的关系数据

一次读懂mybatis中的缓存机制

完成就绪状态后,清除缓存后,JS函数只会运行一次?

Memcached特性及优缺点