Firebase onDisconnect не на 100% надежна?

Я использую Firebase широко и по-прежнему сталкиваюсь только с одной реальной проблемой: onDisconnect не на 100% надежна в моем опыте.

Если вы закрываете компьютер, не закрывая сначала окно, или убиваете браузер, у вас когда-нибудь есть "сборщик мусора", который запускает ваш onDisconnect, иногда это не так.

Мой вопрос заключается в следующем: я просто не использую /.connected на данный момент, я в основном использую простой

userRef.set('status', 1);
userRef.onDisconnect().update({ 'status' : 0 });

Что-то не так с этим подходом? Согласны ли мы с тем, что параметры обновления передаются на сервер во время выполнения строки, а не до выгрузки окна?

NB: Я пытаюсь сохранить статус нескольких окон, используя следующий подход, чтобы сохранить статус в 1, если другое окно закрыто:

userRef.child('status').on('value', function(snap) {
  if (snap.val() != 1) {
    userRef.set('status', 1);
  }
});

Я не понимаю, как это могло быть связано, но...

МОЕ РЕШЕНИЕ: На самом деле я просто пропустил ту часть, где вы узнали, что onDisconnect запускается только один раз. Чтобы получить постоянное onDisconnect, вам необходимо реализовать базовое упорство.

Helpers.onConnected = function(callback) {
    var connectedRef = lm.newFirebase('.info/connected');
    var fn =  connectedRef.on('value', function(snap) {
      if (snap.val() === true) {
          if (callback) callback();
      }
    });
    var returned = {};
    returned.cancel = function() {
        connectedRef.off('value', fn);
    };
    return returned;
};       

Простой вариант:

        this._onConnected = lm.helpers.onConnected(function() {
            this.firebase.onDisconnect().update({ 'tu': 0 });
        }.bind(this));

И затем отменить:

        if (this._onConnected) this._onConnected.cancel();
        this.firebase.onDisconnect().cancel();

Ответ 1

Вы всегда должны вызывать операцию onDisconnect() ПЕРЕД вызовом операции set(). Таким образом, если соединение потеряно между двумя, вы не получаете данные о зомби.

Также обратите внимание, что в случае, когда сетевое соединение не будет полностью убито, вам, возможно, придется подождать тайм-аут TCP, прежде чем мы сможем обнаружить пользователя как ушедшего и отключить очистку отключения. Очистка произойдет, но это может занять несколько минут.

Ответ 2

После долгих размышлений я обнаружил эту проблему, которая на самом деле происходила в моем случае, и я думаю, что для большинства других, которые приходят на эту страницу для решения.

Таким образом, проблема заключается в том, что accessToken дважды проверяет его accessToken когда 1. onDisconnect ставится в очередь и 2. когда применяется onDsiconnect. Firebase активно не обновляет токены, когда вкладка не видна. Если страница неактивна более чем по истечении срока действия accessToken и закрыта, не фокусируясь на этой вкладке, firebase не разрешит onDisconnect из-за просроченного accessToken.

Решения для этого:

  1. Вы можете получить новый accessToken, установив некоторый интервал, подобный этому:

    let intervalId;
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') {
        if (intervalId) {
          window.clearTimeout(intervalId);
          intervalId = undefined;
        }
      } else {
        firebaseApp.auth().currentUser.getIdToken(true);
    
        intervalId = setInterval(() => {
          firebaseApp.auth().currentUser.getIdToken(true);
        }, intervalDuration);
      }
    });
    
  2. Или вы можете отключить базу данных вручную firebase.database().goOffline() всякий раз, когда видимость вкладки меняется с "видимой".