node.js - Firebase 函数 : How to maintain 'app-global' API client?

标签 node.js firebase google-cloud-firestore google-cloud-functions serverless

如何实现在 Cloud Function 实例和函数调用之间共享的“应用程序范围”全局变量?我想创建一个真正的“全局”对象,该对象在我所有函数的生命周期中仅初始化一次。

上下文:

我的应用的整个后端是 Firestore + Firebase Cloud Functions。也就是说,我混合使用后台 (Firestore) 触发器和 HTTP 函数来实现后端逻辑。此外,我依靠第三方定位服务来持续监听来自传感器的位置更新。我只需要一个客户端实例来订阅这些更新。

问题在于 Firebase/Google Cloud Functions are stateless ,这意味着函数实例不共享内存/对象/状态。如果我调用 functionA、functionB、functionC,将至少创建 3 个 locationService 客户端实例,每个实例单独监听第 3 方服务,因此我们最终会重复调用位置 API 回调。

示例代码:

// index.js
const functions = require("firebase-functions");

exports.locationService = require('./location_service');

this.locationService.initClient();

// define callable/HTTP functions & Firestore triggers
...

// location_service.js
var tracker = require("third-party-tracker-js");

const self = (module.exports = {
    initClient: function () {
        tracker.initialize('apiKey')
        .then((client)=>{
            client.setCallback(async function(payload) {
                console.log("received location update: ", payload)
                // process the payload ...
                // with multiple function instances running at once, we receive as many callbacks for each location update
            })

            client.subscribeProject()
            .then((subscription)=>{
                subscription.subscribe()
                .then((subscribeMsg)=>{
                    console.log("subscribed to project with message: ", subscribeMsg); // success
                });
                // subscription.unsubscribe(); // ??? at what point should we unsubscribe?
            })
            .catch((err)=>{
                throw(err)
            })
        })
        .catch((err)=>{
            throw(err)
        })
    },

});

我意识到我正在尝试做的事情大致相当于在单进程环境中实现守护进程,并且像 Firebase/Google Cloud Functions 这样的无服务器环境似乎并不是为了支持这种需求而设计的,因为每个实例都在运行作为它自己的过程。但我很想听到任何相反的想法和可能的解决方法。

另一个想法...

受到此启发related SO postofficial GCF docs on stateless functions ,我考虑过使用 Firestore 来保存跟踪器值,该值允许我们有条件地初始化 API 客户端。大致是这样的:

// read value from db; only initialize the client if there's no valid subscription
let locSubscriberActive = await getSubscribeStatusFromDb();

if (!locSubscriberActive) {
   this.locationService.initClient();
}

// in `location_service.js`, do setSubscribeStatusToDb(); // set flag to true when we call subscribe(). reset when we get terminated

面临的问题:我在什么时候取消/重置该值?直觉上,我会在初始化客户端的函数实例被回收/终止时这样做。但是,似乎无法知道 Firebase Cloud Function 实例何时终止?我到处搜索,但找不到有关如何检测此类事件的文档...

最佳答案

Cloud Functions 根本不支持您尝试执行的操作。重要的是要认识到,可以为每个部署的功能分配任意数量的服务器实例。这就是 Cloud Functions 扩展和缩小规模以经济高效的方式匹配函数负载的方式。这些实例可能会因任何原因随时终止。当实例终止时,您没有任何指示。

此外,实例在空闲时无法执行任何计算。 CPU 资源在函数终止后被限制,并在该实例上调用下一个函数时再次启动。当函数没有被主动调用时,您不能运行任何“守护程序”代码。我不知道你的 locationService 做了什么,但在函数终止后它肯定什么也不做,无论它如何终止。

对于任何类型的长时间运行或类似守护程序的代码,Cloud Functions 都不是合适的产品。相反,您应该考虑使用另一种产品,让您可以 24/7 不间断地运行代码。 App Engine 和 Compute Engine 是可行的替代方案,您必须仔细考虑是否以及如何希望它们的服务器实例随负载扩展。

关于node.js - Firebase 函数 : How to maintain 'app-global' API client?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69352819/

相关文章:

java - QueryDocumentSnapshot 无法解析

javascript - Node.js Firestore 身份验证问题(当 javascript 工作时)

ios - 从 firestore 获取数据时准备 segue

node.js - JSON 中视频长度位置 0 处出现意外标记 G

javascript - 插入和选择时如何获取查询结果的数量?

node.js - Docker 中的 Nuxt.js : missing dependencies

node.js - 保留在heroku上运行的nodejs应用程序的历史堆栈跟踪

ios - FUIEmailAuth 未声明

java - 如何使用 firebase 数据库更新本地对象

android - 无效的文档引用。文档引用必须有偶数个段,但 mylist 有 1