BUG: chat messages are being sended duplicated

We found a very specific bug:
On ios, if we unsuscribe a channel before going to background, we are correctly unsuscribed.
BUT, if we suscribe again, then we receive all messages duplicated.
If we repeat the process, the we receive them triplicated. Again, 4 times, etc.

This only happens if we unsuscribe before going background. If we unsuscribe normally there is no problem at all.

Any hint about how to fix it?


  • We have investigated more and it sems it happens always when we go to background, even if we hace unsuscribed some time ago
  • I've noticed this as well. Thanks for your info. I just did a test and I see this happening on my app.

    One thing I need to do is clear all displayed messages when the app goes to background. Because when it comes back in focus and I reconnect to chat it adds the messages to my text object again, thus duplicate. So if I get disconnected do to losing focus I need to clear the messages. That way when I reconnect there are no messages currently being shown.

    Now, this seems to be a different issue than what you are describing. I will do some more testing and see if I can produce the bug that you are describing.
  • JohnTube
    JohnTube mod
    edited May 2018
    Hi @Roger, @Teddymac

    Thank you for choosing Photon!

    Each message published inside a channel has a unique ID.
    Message IDs are integers, start from 1 and are incremented with each new message published.
    A chat channel has limited history but the server keeps track of the last message ID published inside the channel per channel.

    The current capacity for a channel's messages history on Photon Cloud is 100.
    e.g. If a user publishes the message n° 573 (chronologically, counting all messages from all users) inside a channel then:

    - the published message will have ID 573
    - the channel will have 100 messages in history: from MsgID=474 to MsgID=573
    - the channel will have Last Msg ID set to 573

    When a user subscribes to a channel he/she can request previous history messages up to the limit mentioned previously.
    In order to request old messages client can tell the server how much messages it wants using "historyLen" ("messagesFromHistory") parameter:

    a- 0: none
    b- X= 1..N: up to X messages <= N. N is the capacity of the channel history.
    c- -1: all the server's saved messages for this channel

    There is an interesting use case where clients unsubscribes and then subscribes back to the same channel, in this case, the user wants only to get the messages he missed when disconnected/unsubscribed. Photon Chat client can tell the server, using LastMsgIDs parameter, the MsgID of the last message it has received from the server for that channel. This way the server can send back only the messages that were published after that messages if any. Of course, if the user stays disconnected for a long time and messages published during this absence exceed the history messages capacity then some messages will be missed. <b class="Bold">There is one big requirement for this: the client should keep track and cache the ID of the last message received per channel.

    You can also combine the "historyLen"/"messagesFromHistory" parameter with "LastMsgId" parameter per channel to receive the last missed messages if any up to a certain number ("X") to avoid receiving a lot especially if you are going to display only a few or if you are worried it might cause some performance degradation for the device if it's limited somehow.

    I found out that the "lastMsgId" was implemented in our codebase but did not make it to the SDKs for some reason.
    I apologize for that.
    Here is the snippet you could add to ChatClient and start testing, you should cache lastMsgId per channel yourself though.
    /// <summary>
            /// Sends operation to subscribe to a list of channels by name and possibly retrieve messages we did not receive while unsubscribed.
            /// </summary>
            /// <param name="channels">List of channels to subscribe to. Avoid null or empty values.</param>
            /// <param name="lastMsgIds">ID of last message received per channel. Useful when re subscribing to receive only messages we missed.</param>
            /// <param name="messagesFromHistory">0: no history. 1 and higher: number of messages in history. -1: all available history.</param>
            /// <returns>If the operation could be sent at all (Example: Fails if not connected to Chat Server).</returns>
            public bool Subscribe(string[] channels, int[] lastMsgIds, int messagesFromHistory = -1)
                if (!this.CanChat)
                    if (this.DebugOut >= DebugLevel.ERROR)
                        this.listener.DebugReturn(DebugLevel.ERROR, "Subscribe called while not connected to front end server.");
                    return false;
                if (channels == null || channels.Length == 0)
                    if (this.DebugOut >= DebugLevel.WARNING)
                        this.listener.DebugReturn(DebugLevel.WARNING, "Subscribe can't be called for empty or null channels-list.");
                    return false;
                for (int i = 0; i < channels.Length; i++)
                    if (string.IsNullOrEmpty(channels[i]))
                        if (this.DebugOut >= DebugLevel.ERROR)
                            this.listener.DebugReturn(DebugLevel.ERROR, string.Format("Subscribe can't be called with a null or empty channel name at index {0}.", i));
                        return false;
                if (lastMsgIds == null || lastMsgIds.Length != channels.Length)
                    if (this.DebugOut >= DebugLevel.ERROR)
                        this.listener.DebugReturn(DebugLevel.ERROR, "Subscribe can't be called when \"lastMsgIds\" array is null or does not have the same length as \"channels\" array.");
                    return false;
                Dictionary<byte, object> opParameters = new Dictionary<byte, object>
                    { ChatParameterCode.Channels, channels },
                    { ChatParameterCode.MsgIds,  lastMsgIds},
                    { ChatParameterCode.HistoryLength, messagesFromHistory }
                return this.chatPeer.OpCustom(ChatOperationCode.Subscribe, opParameters, true);
  • Thanks so much for this info, it is extremely helpful. I have a couple questions...

    1. How do we get the ids of the messages we receive? The OnGetMessages method has the object[] messages param but there are no ids. Should we attempt to count the messages we receive?

    2. Do we need to unsubscribe from channels when we are disconnected from the server? Like when an app loses focus on mobile and gets disconnected from the server, does the server automatically unsubscribe clients on disconnects?
  • very good questions @Teddymac

    1. You can get the "LastMsgId" manually for the time being, add the following line in HandleChatMessagesEvent inside "ChatClient.cs". You can also optionally add a property or a field inside ChatChannel to set the "LastMsgId":
    var lastMsgId = eventData[ChatParameterCode.MsgId];
    We will add this to the SDK as well.

    2. When the server detects that a client is disconnected it removes it from all subscribed channels. In cases of unexpected disconnects, there is a server timeout for each client after which if the client does not reconnect it should be considered disconnected. So in general no need to unsubscribe on disconnect.
  • Ok, great. I've added it in now and it looks to be calculating the last message id correctly. Now I just need to put that info to use :)

    Thanks much!