Firestore Real Time更新NodeJS中的连接

时间:2019-02-11 11:09:00

标签: node.js firebase websocket google-cloud-firestore

我正在开发一个NodeJS Web应用程序,以通过Admin SDK从Firestore DB接收实时更新。

这是Firestore对象的初始化代码。部署应用程序(在AWS Elastic Beanstalk上)后,它仅执行一次:

const admin = require('firebase-admin');

var serviceAccount = require('./../key.json');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount)
});

var db = admin.firestore();

FUNC.firestore = db;

然后,我在websocket通信中使用此firestore对象将实时更新发送到浏览器。这个想法是使用服务器作为浏览器和Firestore之间的代理。

socket.on('open', function (client) {
    var query = FUNC.firestore.collection("notifications").doc(client.user.id.toString()).collection("global");
    query.onSnapshot(querySnapshot => {
        querySnapshot.docChanges().forEach(change => {
            client.send({ id: change.doc.id, body: change.doc.data(), type: change.type });
        });
    }, err => {
        console.log(`Encountered error: ${err}`);
    });
});

socket.on('close', function (client) {
    var unsub = FUNC.firestore.collection("notifications").doc(client.user.id.toString()).collection("global").onSnapshot(() => {
    });
    unsub();
});

它可以正常工作一段时间,但是几个小时后,客户端停止接收onSnapshot()更新,并且一段时间后服务器记录错误:Encountered error: Error: 10 ABORTED: The operation was aborted.

怎么了?我应该在每个连接上初始化firestore吗?是否存在生命周期错误?

谢谢

编辑(一个非常糟糕的解决方案)

我尝试为每个登录用户创建一个firebase-admin应用实例,并以此方式更改了我的代码

const admin = require('firebase-admin');

var serviceAccount = require('./../key.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

FUNC.getFirestore = function (user) {
  try {
    user.firebase = admin.app(user.id.toString());
    return user.firebase.firestore();
  } catch(e) {
    //ignore
  }

  var app = admin.initializeApp({
    credential: admin.credential.cert(serviceAccount)
  }, user.id.toString());

  user.firebase = app;

  return user.firebase.firestore();
}

FUNC.removeFirebase = function (user) {
  if (user.firebase) {
    user.firebase.delete();
  }
}

然后是套接字侦听器:

    self.on('open', function (client) {
        var query = FUNC.getFirestore(client.user).collection("notifications").doc(client.user.id.toString()).collection("global");
        query.onSnapshot(querySnapshot => {
            querySnapshot.docChanges().reverse();
            querySnapshot.docChanges().forEach(change => {
                client.send({ id: change.doc.id, body: change.doc.data(), type: change.type });
            });
        }, err => {
            console.log(`Encountered error: ${err}`);
        });
    });

    self.on('close', function (client) {
        var unsub = FUNC.getFirestore(client.user).collection("notifications").doc(client.user.id.toString()).collection("global").onSnapshot(() => {
        });
        unsub();
        FUNC.removeFirebase(client.user);
});

因此,当客户端由于服务器删除其Firebase应用的原因而断开连接时,它可以工作,但是我注意到服务器上的巨大内存泄漏,我需要一些帮助

1 个答案:

答案 0 :(得分:0)

最后,我可以向自己反抗。首先,我尝试过的第二个解决方案是一个非常糟糕的解决方案,因为通过Admin SDK创建的每个新应用都存储在RAM中,拥有20/30用户的应用达到了超过1GB的RAM,这是绝对不能接受的。

因此第一个实现是更好的解决方案,无论如何,我错了在onSnapshot侦听器生命周期中注册/注销。每个onSnapshot()调用都返回一个不同的函数,即使在同一引用上被调用也是如此。因此,我没有打开套接字,而是关闭了监听器,而是打开了另一个监听器。这应该是这样:

socket.on('open', function (client) {
    var query = FUNC.firestore.collection("notifications").doc(client.user.id.toString()).collection("global");
    client.user.firestoreUnsub = query.onSnapshot(querySnapshot => {
        querySnapshot.docChanges().forEach(change => {
            client.send({ id: change.doc.id, body: change.doc.data(), type: change.type });
        });
    }, err => {
        console.log(`Encountered error: ${err}`);
    });
});

socket.on('close', function (client) {
    client.user.firestoreUnsub();
});

将近48小时后,侦听器仍然可以正常工作,并且不会发生内存泄漏。