Firestore Real Time обновляет соединение в NodeJS - PullRequest
0 голосов
/ 11 февраля 2019

Я разрабатываю веб-приложение NodeJS для получения обновлений в реальном времени из базы данных Firestore через Admin SDK.

Это код инициализации объекта 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;

Затем я использую этот объект firestore в сообщении websocket для отправки обновлений в реальном времени в браузер.Идея состоит в том, чтобы использовать сервер в качестве прокси между браузером и 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 голосов
/ 17 февраля 2019

Наконец я могу ответить от себя.Прежде всего, второе решение, которое я попробовал, очень плохое, потому что каждое новое приложение, созданное с помощью Admin SDK, хранится в ОЗУ, и для 20/30 пользователей приложение получает более 1 ГБ ОЗУ, что абсолютно недопустимо.

Таким образом, первая реализация была лучшим решением, в любом случае я ошибся в регистрации / отмене регистрации на жизненном цикле приемника приемника.Каждый вызов 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 часов слушатели по-прежнему работают без проблем и не происходит утечек памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...