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
.
Решения для этого:
-
Вы можете получить новый 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);
}
});
-
Или вы можете отключить базу данных вручную firebase.database().goOffline()
всякий раз, когда видимость вкладки меняется с "видимой".