Default behavior for multiple clients with same bare JID and priority

I’m doing some simple testing to understand the (default) behavior of Openfire when multiple clients are connected (and disconnected/reconnected) that have the same bare JID and priority. To test this I wrote a pretty trivial client program in Java, using the Smack library:

package com.test.testxmppclient;

import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jxmpp.jid.EntityBareJid;

import java.io.IOException;

public class FakeAnyClient {
	public static void main(String[] args) throws SmackException, IOException, XMPPException, InterruptedException {
		XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
				.setUsernameAndPassword("client-a", "client-a")
				.setXmppDomain("test.com")
				.setHost("localhost")
				.setSecurityMode(XMPPTCPConnectionConfiguration.SecurityMode.disabled)
				.build();
		AbstractXMPPConnection connection = new XMPPTCPConnection(config);
		connection.connect();
		connection.login();
		System.out.println("Logged in as " + connection.getUser());
		Presence presence = new Presence(Presence.Type.available);
		presence.setPriority(0);
		connection.sendStanza(presence);
		
		ChatManager chatManager = ChatManager.getInstanceFor(connection);
		chatManager.addIncomingListener(new IncomingChatMessageListener() {
			@Override
			public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
				System.out.println("New message from " + from + ": " + message.getBody());
			}
		});
		
		System.in.read();
		connection.disconnect();
	}
}

I’d start 2 instances like this, and I run a third client, connecting with different credentials (“client-b”) using an off-the-shelf XMPP chat program (gajim in my case).
Now when I send some chat messages from client-b (gajim) to client-a (2 instances my program), each of those messages gets delivered to one of the two instances, but in a somewhat piculiar pattern: sometimes all the messages get delivered to the same instance while other times the first message gets delivered to one instance while the remaining messages get delivered to the other instance. This behavior already seems very interesting and I would like to understand it better, but what is even more interesting and the main point of what I would like to understand is what happens when one of my “client-a” programs, which received some (or all) of the messages, terminates.
When I gracefully shut it down (by pressing any key in this case) and the connection.disconnect(); is called nothing surprising happens; thats just it, and any next mesasges will be delivered to the remaining instance. However when I kill it (or just exit it without calling connection.disconnect();) I see different things happening each time:

  • Sometimes all of the messages that instance received get redelivered to the other instance
  • Sometimes some of the messages that instance received get redelivered to the other instance
  • Sometimes nothing happens ; none of the messages that instance received get redelivered to the other instance
    When there is no other client and the ‘killed’ client just reconnects shortly after, I havent seen any messages been redilvered to the “new” instance.

The best I can make of this that when a client “disappears” (without calling disconnect) and there are other clients (with the same priority?) there is some mechanism that redelivers messages which have been delivered less than X time ago. However I could not find any documentation about this while I imagine behavior like that would have to have been thoughtfully designed.
So finally my questions:

  • Is this behavior as expected?
  • Is there any documentation about it?
  • Can it be adjusted? (ie, can such redelivery be disabled, can the timeout for it be changed)?
  • Can a client somehow indicate that a message is handled and therefore should not be redelived in case the connection is lost (ie, an ACK)?
  • This behavior also implies that messages which have been delivered will still be kept by the server for some time (at least until this supposed redelivery timeout expired). I did not find any place in the database where they seem to be kept. Where are they kept?

I hope someone can help me out here, as using xmpp/Openfire in my application requires thourough understanding of what happens in these cases.

My answer is not something that will explain all your questions, but might help to solve the issue. what you can do so that all clients receive the messages that were sent to the user is: Go to ‘Server>Server Manager>System Properties’ and set this property to ‘true’ ‘route.really-all-resources’.
the other thing that might also help to never lose any messages is to install the monitoring plugin to activate MAM.

Thanks for your message. I’m aware of this option, it’s sort of the only info I could actually find related to configuring the delivery mechanism. However my goal here is not to get the messages deliverd to all clients, it’s sort of the opposite: to prevent getting the same mesage delivered to more than one client in unexpected ways.

Some background: My use-case is an IOT setup that I inherited responsibility for. The clients are the devices (~50K) in the field which connect to Openfire through XMPP (24/7), and one client that represents our back-end. This back-end client is implemented using the Smack library and ‘chats’ with all the device clients. My current endeavor is to make this back-end connection more robust and scalable. In other words: Have some redundancy. Because right now, when this one back-end client breaks, or it’s connection is interrupted, or needs to be restarted for maintenance or whatever, basically the connection to all devices in the field is down, which practically means a complete outage of our service.

My current understanding is that, given what I wrote above, this can basically not be solved in a straightforward way with ‘vanilla’ Openfire and XMPP connections. I’m currently looking into other options, including writing plugins for Openfire to change it’s routing behavior or connect to it in different ways. I was hoping that maybe I missed something, as Openfire/XMPP seems to be used in IOT setups by others as well and I cant imagine I’d be the first to run into this.