ConnectionManager.onChannelMessage()接收到具有不同connectionSerial的消息,但是与之前的消息ID相同;丢弃

时间:2018-05-25 17:03:58

标签: ably-realtime

将Ably Realtime用于基于网络的预订系统。

我在js控制台中始终遇到一些错误,尽管一切正常。

基本上,有一个日期选择器,当访问者选择日期时,我将全局变量day设置为日期(类似2018-05-25)并调用VisitorMessages.start(),订阅它们发送到消息并使它们出现在频道visitor:2018-05-25上,并从所有其他频道取消订阅。

我还有一个visitor:all频道,每个人都可以收到消息并且不需要在场。

这就是我正在做的事情(请原谅CoffeeScript):

VisitorMessages =
  realtime: null
  connected_first_time: false
  start: ->
    unless @realtime
      @realtime = new Ably.Realtime
        authUrl: '/auth'
        recover: (lastConnectionDetails, cb) ->
          cb(true)
          return

    @unsubscribe()

    dayChannel = @realtime.channels.get("visitor:#{day}")
    allChannel = @realtime.channels.get("visitor:all")

    allChannel.subscribe (m) ->
      switch m.name
        when " . . . "
          # . . .
    dayChannel.subscribe (m) ->
      switch m.name
        when " . . . "
          # . . .

    dayChannel.presence.subscribe 'enter', (member) -> VisitorMessages.setNumOnline(dayChannel)
    dayChannel.presence.subscribe 'leave', (member) -> VisitorMessages.setNumOnline(dayChannel)
    dayChannel.presence.enter()
    VisitorMessages.setNumOnline(dayChannel)

    @realtime.connection.on 'connected', ->
      VisitorMessages.refreshData() # not showing this function here
      VisitorMessages.connected_first_time = true # the refreshData() function returns if this is false
      dayChannel = VisitorMessages.realtime.channels.get("visitor:#{day}")
      dayChannel.attach()
      dayChannel.presence.enter()
      VisitorMessages.setNumOnline(dayChannel)
      allChannel = VisitorMessages.realtime.channels.get("visitor:all")
      allChannel.attach()

  setNumOnline: (channel) ->
    channel.presence.get (err, members) ->
      # I use ractive.js to manipulate the DOM
      ractive.set('number_online', members.length)

  unsubscribe: ->
    for channelName of VisitorMessages.realtime.channels.all
      unless channelName == 'visitor:all'
        channel = VisitorMessages.realtime.channels.get(channelName)
        channel.presence.leave()
        channel.presence.unsubscribe()
        channel.unsubscribe()
        channel.detach()
        VisitorMessages.realtime.channels.release(channelName)

在js控制台中,访问者获得了大量这些内容:

Ably: ConnectionManager.onChannelMessage() received message with different connectionSerial, but same message id as a previous; discarding

有时这个:

Ably: RealtimePresence._ensureMyMembersPresent(): Presence auto-re-enter failed: [c: Unable to enter presence channel (incompatible state); code=90001]

而且,当切换到另一个日期(设置日期并调用VisitorMessages.start()时),他们会得到这个:

Channels.onChannelMessage(): received event for non-existent channel: visitor:2018-05-26

我知道这可能是因为我在切换日期时明确地发布了频道,但是当我没有这样做时,VisitorMessages.realtime.channels.all将包含我加入的所有频道,而我仍然收到未订阅频道的消息。

所以,这里有很多不同的东西,但有人可以看到我的方法中的一些重大缺陷或帮助我理解为什么会发生这些错误?同样,一切正常,但有些事情是不对的!

谢谢!

以上代码编译成javascript:

var VisitorMessages;

VisitorMessages = {
  realtime: null,
  connected_first_time: false,
  start: function() {
    var allChannel, dayChannel;
    if (!this.realtime) {
      this.realtime = new Ably.Realtime({
        authUrl: '/auth',
        recover: function(lastConnectionDetails, cb) {
          cb(true);
        }
      });
    }
    this.unsubscribe();
    dayChannel = this.realtime.channels.get("visitor:" + day);
    allChannel = this.realtime.channels.get("visitor:all");
    allChannel.subscribe(function(m) {
      switch (m.name) {
        case " . . . ":
          // . . .
      }
    });
    dayChannel.subscribe(function(m) {
      switch (m.name) {
        case " . . . ":
          // . . .
      }
    });
    dayChannel.presence.subscribe('enter', function(member) {
      VisitorMessages.setNumOnline(dayChannel);
    });
    dayChannel.presence.subscribe('leave', function(member) {
      VisitorMessages.setNumOnline(dayChannel);
    });
    dayChannel.presence.enter();
    VisitorMessages.setNumOnline(dayChannel);
    return this.realtime.connection.on('connected', function() {
      VisitorMessages.refreshData();
      VisitorMessages.connected_first_time = true;
      dayChannel = VisitorMessages.realtime.channels.get("visitor:" + day);
      dayChannel.attach();
      dayChannel.presence.enter();
      VisitorMessages.setNumOnline(dayChannel);
      allChannel = VisitorMessages.realtime.channels.get("visitor:all");
      allChannel.attach();
    });
  },
  setNumOnline: function(channel) {
    channel.presence.get(function(err, members) {
      ractive.set('number_online', members.length);
    });
  },
  unsubscribe: function() {
    var channel, channelName, results;
    for (channelName in VisitorMessages.realtime.channels.all) {
      if (channelName !== 'visitor:all') {
        channel = VisitorMessages.realtime.channels.get(channelName);
        channel.presence.leave();
        channel.presence.unsubscribe();
        channel.unsubscribe();
        channel.detach();
        VisitorMessages.realtime.channels.release(channelName);
      }
    }
  }
};

1 个答案:

答案 0 :(得分:1)

我是Ably的工程师。

没有特别重要的图片,只是在这里发生了许多不同的事情。

  

Ably:ConnectionManager.onChannelMessage()收到的消息带有不同的connectionSerial,但消息ID与之前相同;丢弃

这意味着客户端lib已收到多个邮件副本,并自动对其进行重复数据删除。众所周知,在客户端lib执行实时彗星 - > websocket升级之后偶尔会发生这种情况。如果它一直发生,可能还有其他事情发生 - 联系我们,我们会尝试实时调试。

  

Channels.onChannelMessage():收到不存在频道的活动:访客:2018-05-26

正如您所正确指出的那样,那是因为您正在发布频道。 channels.release()是一个很少使用的功能,它真的只适用于客户端连接和分离channels.all共同开始占用大量内存的众多频道,因此release()删除它们以便它们可以垃圾收集。这不是99%的人需要做或知道的事情 - 我认为它甚至不包含在我们的api文档中。它肯定永远不会用在尚未分离的通道上,这将导致未定义的行为。

当您在代码中调用它时,即使您已调用detach(),该频道确实尚未分离。每the api docs for channel#detach(),它是一个异步操作 - 它请求从Ably分离,并在此期间将通道置于detaching状态。如果有必要释放一个频道(而且客户端几乎从不这样做),则应该在回调detach()(或once('detached')监听器)时完成。

  

当我没有这样做时,VisitorMessages.realtime.channels.all将包含我加入的所有频道

是的,但没关系,在那个对象中并不意味着他们是附属的。您可以通过为state'attached'

的那些条目过滤这些条目来仅显示附加条目
  

我还在接收未订阅频道的消息。

取消订阅是一个本地操作(它只是同步删除你添加的监听器);如果您想阻止lib接收来自服务器的消息,您需要从频道中分离 - 请参阅channels/messages docs

(如果您的意思是在调用unsubscribe()之后仍然调用了您的消息侦听器,或者lib仍然在detached状态的通道上接收消息,那么这些消息都不可能 - 你的取消订阅代码已被破坏(我不太擅长coffeescript),或者被调用的听众不适合您认为的频道,或者ably-js中存在错误。设置log: {level: 4}在lib构造函数中将启用调试日志记录,它可以帮助您查看lib正在执行的操作;如果您需要帮助分析日志,请告诉我们。)

  

Ably: RealtimePresence._ensureMyMembersPresent(): Presence auto-re-enter failed: [c: Unable to enter presence channel (incompatible state); code=90001]

通常情况下,这意味着频道在被暂停后会尝试自动重新连接并重新进入(例如,因为您与互联网断开了大约2分钟),但是无法通知,例如因为客户端现在使用的是没有权限访问该通道的令牌。

但在你的情况下,我猜你手动释放()d的频道会产生噪音,然后由于服务器永远不会被告知他们已经detached,他们就会陷入困境。

(我实际上刚刚提交了一个功能建议,要求在channel.release()上设置一个警卫,以阻止您为处于活动状态的频道执行此操作 - https://github.com/ably/docs/issues/437)。