首页 > 解决方案 > Azure Node.js Function App 的单例 CosmosDB 客户端

问题描述

我有一个 EventGrid 触发的 Node.js Azure 函数应用。

它可以同时接收 100 个呼叫来运行。如果进程成功或失败,它会写入 CosmosDB。

然而,CosmosDB 客户端的初始化是一个代价高昂且运行时间长的过程,因此我想在函数应用的所有 100 个实例中将这个初始化的客户端作为单例共享。

查看 Node.js 文档,它指出如果导出对象,模块将被缓存(相同实例)。https://nodejs.org/api/modules.html#modules_caching即,如果我返回一个对象,它将充当单例。

当我在 Azure 中测试我的代码时,我看到它被一遍又一遍地调用。

问题:如何在所有并发“线程”中初始化我的 CosmosDB 客户端一次。

在下面的示例代码中,我使用 5000m/s 的长时间运行操作来伪造长期运行的 Cosmos 初始化。

我昂贵的操作模块返回一个对象。

昂贵的Operation.js

const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));

let value = null;

const getInstance = async (context) => {
    if(value !== null) return value;
    context.log("Long running process started...")
    await snooze(5000);
    value = 5;
    return value;
}

exports.something = {
    getInstance
};

index.js

const { something } = require("../expensiveOperation");

module.exports = async function (context, req) {
  context.log("JavaScript HTTP trigger function processed a request.");

  var first = await something.getInstance(context);
  context.done();
};

标签: node.jsazureazure-functions

解决方案


tl; dr
您做得对,但您的思维模式不正确。

长答案
我想为术语添加一些清晰度。
有函数宿主、实例和调用。文档
可以 在这里指导我们。 你的方法是正确的,但你的思维模式并不完全准确。 Azure Function 主机是黑匣子,它控制内部发生的事情以及设置新实例的时间。 根据事件网格中的消息数量,它会将您的请求映射到新实例,并且无法控制将消息映射到哪个实例。 每个实例都有自己的 CosmosDB 客户端。

Azure 函数模型

Application Insights 可以帮助您查看以最小延迟运行的实例数量:
实时指标


推荐阅读