【问题标题】:NodeJS array and firebase reference getting garbage collectedNodeJS 数组和 firebase 引用获取垃圾收集
【发布时间】:2021-08-19 14:33:49
【问题描述】:

我希望能够在第一个用户连接到 socket.io 房间时创建一些 firebase 引用,然后监听这些 firebase 引用的更改,并写入文件。

现在我的方法是拥有一个全局 Map 对象,然后将 firebase 引用和文件名作为对象的一部分分配给数组。然后将对象存储到全局地图。 不幸的是,一旦第一次连接的功能结束,引用就会丢失。我可以通过让另一个用户连接/刷新页面并记录全局地图来看到这一点。

这是我的代码的样子。

io.on('connect', (socket) => {
    io.to(socket.id).emit('create-room');
    socket.on('join-room', (roomId: string) => {
      socket.join(roomId);
      try {
        console.log(activeWorkers)
        if (!activeWorkers.get(roomId)) {
          // if not in global map, tell user he is first in room so that we can get additional info
          io.to(socket.id).emit('first-in-room');
        } else {
          console.log(activeWorkers.get(roomId));
        }
      } catch(err) {
        console.log(err);
      }
    });
    socket.on('create-worker', async (roomId: string, additionalInfo: string) => {
      // first user sent back additional info;
      let firebaseRefObj = new FirebaseRefObj(roomId, additionalInfo); // an object that stores the references and file paths

      activeWorkers.set(roomId, {
        id: roomId,
        worker: firebaseRefObj
      }); // store in global map
      firebaseRefObj.createRefs(); // create references, the references add initial values to firebase, then watch for changes to update local files.
    })
    socket.on("disconnect", () => {
      socket.removeAllListeners();
    });
  })

【问题讨论】:

  • 忽略题为 Javascript 开发者,他没有意识到 redis 也使用 RAM。我想知道您的脚本是在专用 VM 上运行还是在 Cloud Functions 上运行,因为 Cloud Functions 也可能会超时,并且并非旨在将数据保留太久。
  • 我真的不明白任何存储媒体如何处理我想要的东西,我想在哪里拥有活跃的 FIREBASE 侦听器。它将存储在 firebase rtd 中的数据写入磁盘。我目前正在本地机器上进行测试,但计划在我想扩展时将其 dockerize。

标签: node.js firebase socket.io


【解决方案1】:

这是因为 socket.io 函数不会从 on 事件中持久化其变量,如果您稍后尝试访问 firebaseRefObj,则必须将其存储到数组或对象映射中,以便您可以将该用户与它重新关联。

您可以使用现有的房间 ID,并将其作为值的名称传递给您的引用列表{[roomId]: firebaseRefObj}

就我个人而言,我强烈推荐这个用例使用enmapenmap 就像 node.js 的 C# 字典。当你启动你的脚本并声明你的变量时,在顶部添加一个新的 enmap 来存储你的 ref 对象。

我相信以下方法会起作用:

const Enmap = require("enmap");
const FirebaseRefs = new Enmap();

// ...
FirebaseRefs.set(RoomId, FirebaseRefsObj);

您可以在此处阅读基础知识:https://enmap.evie.dev/usage/basic

来源:https://www.npmjs.com/package/enmap

【讨论】:

  • 问题是我有一个全局 Map() ,我将 firebaseRefsObj 分配给它。问题是,firebaseRefsObj 仍在内存中,但是该类包含三个数组,并且所有这些数组都是空的。 1个数组是字符串数组,另一个是firebase refs。我会给enmap一个镜头。
  • 我看到了将其存储在全局地图中的参考,但您没有将 firebaseRefObj 传递给它,仅:roomIDfirepad - 所以当 socket.on("create-worker") 解析时,它丢失了
  • 哦,我刚刚注意到我有一个严重的重构错误。无论如何,我更新了我的帖子。我正在存储 roomId 和 firebaseRefObj,然后调用 createRefs(),它将带有值处理程序的 firebase 引用添加到 firebaseRefObj 中的数组。如果我先保存,然后添加 refs,或者相反,这并不重要。第二个用户/第一个用户重新加载的数组为空
  • 您应该在创建新值之前检查该值是否存在,不是吗?否则,这是一个标准的竞争条件
  • 我怀疑客户端以及您调用套接字连接的方式存在问题,请仔细检查您的应用程序流程以及垃圾收集是否仍然存在问题:worker: new FirebaseRefObj(roomId, additionalInfo);
【解决方案2】:

Enmap 是一个非常好的解决方案,但我的问题在于我正在使用我的 firebase 引用。我在内部使用了firepad,它把自己和firebase引用一起带出了范围。

移除 Firepad 解决了我的问题。

【讨论】:

    猜你喜欢
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    相关资源
    最近更新 更多