ConnectionManager.onChannelMessage() получил сообщение с другим connectionSerial, но тем же идентификатором сообщения, что и предыдущий; отбрасывание

Использование 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);
      }
    }
  }
};

person Jason Galuten    schedule 25.05.2018    source источник


Ответы (1)


Я инженер в Ably.

Никакой особой большой картины, просто куча разных вещей, происходящих здесь.

Умело: ConnectionManager.onChannelMessage() получил сообщение с другим connectionSerial, но с тем же идентификатором сообщения, что и предыдущий; отбрасывание

Это означает, что клиентская библиотека получила несколько копий сообщения и автоматически их дедуплицирует. Известно, что это иногда происходит сразу после того, как клиентская библиотека выполняет живое обновление кометы-> websocket. Если это происходит постоянно, возможно, происходит что-то еще — свяжитесь с нами, и мы попробуем отладить его вживую.

Channels.onChannelMessage(): получено событие для несуществующего канала: посетитель: 2018-05-26

Как вы правильно заметили, это потому, что вы выпускаете канал. channels.release() — это редко используемая функция, которая на самом деле полезна только в том случае, когда клиент подключается и отсоединяется от такого количества каналов, что channels.all в совокупности начинает занимать нетривиальный объем памяти, поэтому release() удаляет их, чтобы они могли быть удалены сборщиком мусора. Это не то, что 99% людей когда-либо должны будут делать или знать — я не думаю, что это даже включено в наши API-документы. Его, безусловно, никогда не следует использовать на канале, который еще не отсоединен, это приведет к неопределенному поведению.

Когда вы вызываете его в своем коде, канал действительно еще не отсоединен, даже если вы вызвали detach(). Согласно документам API для channel#detach(), это асинхронный операция - он запрашивает отсоединение от Ably и тем временем переводит канал в состояние detaching. Если необходимо освободить канал (а на стороне клиента этого почти никогда не бывает), это нужно делать в обратном вызове detach() (или слушателю once('detached')).

когда я этого не делал, VisitorMessages.realtime.channels.all будет содержать все каналы, к которым я когда-либо присоединялся

Да, но это нормально, нахождение в этом объекте не означает, что они привязаны. Вы можете показать только прикрепленные, отфильтровав те записи, у которых state равно 'attached'.

и я все еще получал сообщения для отписавшихся каналов.

Отписка — локальная операция (она просто синхронно удаляет добавленный вами слушатель); если вы хотите, чтобы библиотека не получала сообщения с сервера, вам нужно отсоединиться от канала — см. документы каналов/сообщений

(Если вы имеете в виду, что ваш прослушиватель сообщений все еще вызывается после того, как вы вызываете unsubscribe(), или библиотека все еще получает сообщения на канале, который находится в состоянии detached, ни одно из этих действий не должно быть возможным — либо ваш код отписки не работает (я не Боюсь, я не слишком хорошо знаю coffeescript), или вызываемый слушатель не для канала, о котором вы думали, или есть ошибка в able-js. Установка log: {level: 4} в конструкторе lib включит ведение журнала отладки, что может помочь вы видите, что делает библиотека, и дайте нам знать, если вам нужна помощь в анализе журнала).

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

Обычно это означает, что канал пытался автоматически повторно подключиться и повторно войти после приостановки (например, из-за того, что вы были отключены от Интернета более 2 минут), но не смог, например. потому что клиент теперь использует токен, у которого нет разрешений на доступ к этому каналу.

Но в вашем случае я бы предположил, что это шум от каналов, которые вы вручную освободили () и затем оставили в подвешенном состоянии, поскольку сервер никогда не мог сказать им, что они были detached.

(На самом деле я только что подал предложение о функции, чтобы иметь защиту для channels.release(), чтобы вы не делали это для каналов в активном состоянии - https://github.com/ably/docs/issues/437 ).

person Simon Woolf    schedule 25.05.2018
comment
Спасибо! Я обновил свой вопрос, включив в него версию кода javascript (в любом случае никогда не следовало публиковать CoffeeScript). - person Jason Galuten; 26.05.2018
comment
Хорошо, да. Я удалил строку, которая освобождает канал, и он позаботился обо всем, кроме первой ошибки (заголовок поста) о сообщении с другим серийным номером подключения. Это все еще происходит каждый раз при первом подключении. Если вы можете помочь мне отладить его вживую, это было бы здорово. - person Jason Galuten; 26.05.2018
comment
Как бы то ни было, идея выпустить канал появилась здесь: грамотно .io/documentation/realtime/channels-messages#subscribe (в конце раздела Рекомендации по методу подписки) - person Jason Galuten; 26.05.2018
comment
Итак, ошибка в заголовке вопроса связана не с моим кодом, а с проблемой Ably, которая не вызывает никаких проблем. Я установлю для журнала значение 0 в рабочей среде, чтобы подавить это сообщение на клиенте. - person Jason Galuten; 01.06.2018