You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Riverpod中Appwrite实时订阅取消订阅时的Missing channels(1008)问题

问题分析

你遇到的是Flutter结合Riverpod使用Appwrite实时订阅时的异常:单文档订阅功能正常,但多文档订阅场景下,页面关闭导致autoDispose Provider销毁时,Appwrite抛出Missing channels (1008)未处理异常。错误日志明确指向Realtime通道缺失问题。

已知前提

  • 所有订阅文档均存在于目标集合,用户拥有读取权限
  • Appwrite实例为全局单例,无重复实例

可能原因

当多个TestNotifier实例(对应不同文档)共享同一个Appwrite Realtime单例时,多订阅的close()操作存在异步竞态:某一个订阅关闭后,后续其他订阅的关闭请求可能尝试移除已不存在的通道,或因Realtime连接状态变化触发通道校验失败。


解决方案

方案1:捕获close操作的异常

在dispose方法中用try-catch包裹订阅关闭逻辑,忽略已知的通道缺失异常:

@override
void dispose() {
  if (_subscription != null) {
    try {
      _subscription?.close();
    } on AppwriteException catch (e) {
      // 仅忽略1008通道缺失异常,其他异常正常抛出
      if (e.code != 1008) rethrow;
    }
  }
  super.dispose();
}

方案2:改用集合级订阅(推荐)

放弃为每个文档创建独立订阅,改为订阅整个集合并在本地过滤目标文档,减少Realtime连接数并避免多订阅关闭冲突:

void subscribe() {
  final realtime = ref.watch(AppwriteDependencies.realtime);
  // 订阅整个stats集合的所有文档变更
  _subscription = realtime.subscribe(['databases.bracket_db.collections.stats.documents']);

  _subscription?.stream.listen((response) {
    // 仅处理当前Provider关注的文档ID
    if (response.payload['\$id'] == docID) {
      final bracketStats = BracketStats.fromJson(response.payload);
      state = bracketStats;
    }
  });
}

这种方式下,无论多少个Provider实例,都共享同一个Realtime连接,仅在本地过滤数据,从根源避免多订阅关闭的通道冲突问题。

方案3:稳定Realtime实例生命周期

确保AppwriteDependencies.realtime提供的是非autoDispose的全局单例Provider,保证Realtime实例在所有订阅Provider销毁前始终存在,避免因实例提前销毁导致的通道操作失败。


验证建议

  • 测试多文档场景下的页面关闭流程,确认异常是否消失
  • 查看Appwrite控制台的Realtime连接统计,验证方案2的连接数是否符合预期(仅1个集合连接)

内容的提问来源于stack exchange,提问作者monzim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 02:06:04