首页 > 解决方案 > 当 Internet 出现故障时,ServerValue.increment 无法正常工作

问题描述

添加ServerValue.increment()Add increment() for atomic field value increment #2437)是一个好消息,因为它允许在 Firebase RTDB 中自动增加字段值。

我有一个保存库存的应用程序,这个功能很关键,因为它允许更新库存,而不管用户是否有时离线。但是,我开始注意到有时该函数会执行两次,这完全以错误的方式错误地列出了库存。

为了隔离问题,我决定进行以下测试,这表明ServerValue.Increment()当连接从联机到脱机时工作错误:

  1. for loop function1 到 200:

    for (var i = 1; i <= 200; i++) {
      testBloc.incrementTest(i);
      print('Pos: $i');
    }
    
  2. 该函数incrementTest(i)必须增加两个变量:(position从 1 中的 1 计数到 200)和sum(加 1 + 2 + 3, ..., + 200 应该得到 20,100)

        Future<bool> incrementTest(int value) async {    
         try {    
    
           db.child('test/position')
             .set(ServerValue.increment(1));     
    
           db.child('test/sum')
             .set(ServerValue.increment(value));     
    
         } catch (e) {
           print(e);
         }  
    
    
          return true;
     }
    

请注意, db 指的是 Firebase 实例 ( FirebaseDatabase.instance.reference())

随之而来的是测试:

测试 1:100% 在线。通过

该函数正常工作,将两个变量传递给正确的结果(在 Firebase 控制台中):

职位:200

总和:20100

测试 2:100% 离线。通过

为此,我在飞行模式下使用了物理设备,然后执行了for loop function,当函数完成执行后,我停用了飞行模式并在 firebase 控制台中检查了结果,结果令人满意:

职位:200

总和:20100

测试 3:开始在线,然后转到离线。失败的

这是Internet 连接断开时的典型操作场景。更糟糕的是,当连接断断续续时,您正在地铁上旅行,或者您处于需要离线持久性的低覆盖率站点。为了模拟它,我所做的是for loop function在在线模式下运行,在它完成之前,我将物理设备置于飞行模式。后来我上网完成了测试,并在 Firebase 控制台上查看了结果。在所有情况下,获得的结果都是不正确的。以下是一些结果:

增量执行两次多次

如您所见,增量错误地重复了 10、18 和 9 次。

我怎样才能避免这种行为?

有没有其他方法可以在 Firebase 中自动增加一个可以在线/离线正常工作的数字?

标签: flutterfirebase-realtime-databaseoffline

解决方案


火力基地在这里

这是增量行为中一个有趣的边缘情况。客户端和服务器之间都无法确定增量是否已执行,因此最终会在重新连接时从客户端重试。据我所知,这个问题只会发生在增量操作中,因为除了事务之外,所有其他写操作都是幂等的,但那些在离线时不起作用。

可以确保每个增量发生一次,但这需要一些工作:

  1. 首先,添加一个 nonce 以唯一标识此操作的写入操作。您可以为此使用按键,但任何其他 UUID 也可以正常工作。将此与您的原始set()调用组合成一个多路径update调用,将 nonce 写入顶级节点,并将服务器端时间戳作为其值。
  2. 现在在顶级位置的安全规则中,仅在没有现有数据时才允许写入。这可以确保您看到的辅助写入被拒绝,并且由于在整个多路径更新中检查安全规则,错误的增量也将被拒绝。
  3. 您可能希望根据其中的时间戳值定期使用 nonce 键清理节点。这对性能无关紧要(因为您在清理期间从不在这里搜索),但可能有助于控制随机数的存储成本。

我还没有将这种方法用于这个特定的用例,但已经为其他人使用过。如果您包含客户端重试,则上述内容实质上构建了您自己的多路径事务机制,这是我过去需要的。但是由于您在这里不需要它,所以没有它会更简单。


推荐阅读