【问题标题】:Firebase onDisconnect not 100% reliable now?Firebase onDisconnect 现在不是 100% 可靠吗?
【发布时间】:2021-02-21 02:33:22
【问题描述】:

我一直在广泛使用 Firebase,但仍然只面临一个实际问题:根据我的经验,onDisconnect 并非 100% 可靠。

如果您在没有先关闭窗口的情况下关闭了计算机,或者关闭了浏览器,则有时会执行“垃圾收集器”来执行 onDisconnect,有时则不会。

我的问题如下:我只是暂时不使用/.connected,我基本上使用一个简单的

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

这种方法有什么问题吗?我们是否同意在执行该行时而不是在窗口卸载之前将更新参数传递给服务器?

注意:我碰巧尝试保持多窗口状态,如果另一个窗口关闭,则使用以下方法将状态保持为 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();

【问题讨论】:

    标签: firebase


    【解决方案1】:

    在调用 set() 操作之前,您应该始终调用 onDisconnect() 操作。这样,如果两者之间的连接丢失,您最终不会得到僵尸数据。

    另请注意,在网络连接未完全终止的情况下,您可能必须等待 TCP 超时,然后我们才能检测到用户已离开并触发断开连接清理。将进行清理,但可能需要几分钟时间。

    【讨论】:

    • 问题是我仍然得到了大约 20% 的 onDisconnect 不幸的是从未被调用,导致人们似乎永远保持联系。您是否有任何方法来了解正在发生的事情,因为它 100% 确定在调用 onDisconnect 时至少几分钟内仍有连接?
    • 客户端断开连接后您等待多长时间?在某些极端情况下,可能需要长达 5 分钟。另外 - 您是否有阻止断开连接操作的安全规则?测试用例也会有所帮助。你有一个超级简单的测试用例的链接吗?
    • 安德鲁,我终于找到了问题的根源。我的错误:我从来没有真正意识到只有在您第一次断开连接时才调用 onDisconnect。这解释了我们遇到的所有错误......我肯定会在您的网站上用红色+粗体表示。
    • 我还可以推荐一个简单的插件吗?我不知道其他项目,但在我们的例子中,我们总是希望在未来的 onDisconnect 上再次调用 onDisconnect(想象一下用户连接不良并且不断断开/重新连接的情况)。我的建议是,如果我们希望在以后每次断开连接时都调用它,我们不能将其作为参数传递给 onDisconnect 吗?看起来像这样:ref.onDisconnect(true).update(down);
    • 这就是我们提供 /.info/connected 端点的原因。我们建议每次连接重新联机时重新建立断开连接处理程序。在此处查看最后的代码 sn-p:firebase.com/docs/managing-presence.html
    【解决方案2】:

    经过大量挖掘,我发现this issue 确实发生在我的案例中,我认为对于大多数其他人来说,他们也来到这个页面寻求解决方案。

    所以问题是当 1.onDisconnect 入队和 2 时,firebase 会检查它的 accessToken 两次。当onDsiconnect 被应用时。 当标签不可见时,Firebase主动刷新令牌。如果页面在accessToken 到期后处于非活动状态并且在没有关注该选项卡的情况下关闭,则由于accessToken 已过期,firebase 将不允许onDisconnect

    解决方案:

    1. 您可以通过设置某种 间隔是这样的:

      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(),只要选项卡可见性从“可见”更改。

    【讨论】:

      【解决方案3】:

      扩展评论:

      This is why we provide the /.info/connected endpoint. 
      We recommend re-establishing the disconnect handler every time the connection comes back online
      

      我按照上面的方法解决了:

      const userRef = Firebase.database().ref('/users/<user-id>')
      
      Firebase.database()
        .ref('.info/connected')
        .on('value', async snap => {
          if (snap.val() === true) {
            await userRef.onDisconnect().remove();
            await userRef.update({ status : 'online' })
          } else {
            await this.userRef.remove()
          }
      });
      

      作为参考,我之前的代码是:

      const userRef = Firebase.database().ref('/users/<user-id>')
      userRef.onDisconnect().remove();
      await userRef.update({ status : 'online' })
      

      这样做的问题是,当您离线并多次重新在线时,onDisconnect 可能无法正常工作

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-04
        • 2020-11-27
        • 1970-01-01
        • 2020-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多