2

I am implementing Active MQ publisher and subscriber in c#. I am using Apache.NMS.ActiveMQ .net client library to communicate with the broker.

  <package id="Apache.NMS" version="1.7.1" targetFramework="net461" />
  <package id="Apache.NMS.ActiveMQ" version="1.7.2" targetFramework="net461" />

ActiveMQ is configured with a fail over setup on 4 servers (.225, .226, .346, .347 - last parts of IP for reference) . The broker url looks something like

failover://tcp://103.24.34.225:61616,tcp://103.24.34.226:61616,tcp://103.24.34.346:61616,tcp://103.24.34.347:61616

Here is how I am publishing

    var brokerUrl = "failover://tcp://103.24.34.225:61616,tcp://103.24.34.226:61616,tcp://103.24.34.346:61616,tcp://103.24.34.347:61616";
    var connectionFactory = new ConnectionFactory(brokerUrl);
    using (var connection = connectionFactory.CreateConnection("conn1", "conn$34"))
    {
        connection.ClientId = "TESTPUBLISHER";
        connection.AcknowledgementMode = AcknowledgementMode.ClientAcknowledge;
        connection.Start();

        var session = connection.CreateSession();
        var topic = new ActiveMQTopic("ACCOUNT.UPDATE");
        var producer = session.CreateProducer(topic);


        var msg = "43342_test"; //DateTime.Now.ToString("yyyyMdHHmmss_fff") + "-TEST";
        var textMessage = producer.CreateTextMessage(msg);

        textMessage.Properties.SetString("Topic", "ACCOUNT.UPDATE");
        textMessage.Properties.SetString("Action", "UPDATE");
        textMessage.Properties.SetString("DataContractType", "Account");

        producer.Send(textMessage, MsgDeliveryMode.Persistent, MsgPriority.Normal, new TimeSpan(0, 0, 60, 0, 0));

     }

Here is how I am subscribing to the topic. This code is setup such that, multiple shared subscribers can listen for incoming messages. I was told I have to use Virtual Topics to accomplish that. So I configured my subscriber to use Virtual Topic and it is hosted inside a Windows Service project. I am using Acknowledgement Mode to be ClientAcknowledge, so that unless a message is acknowledged, it should keep coming back. Below code snippet is representing just the important subscriber portion of the windows service.

var brokerUrl = "failover://tcp://103.24.34.225:61616,tcp://103.24.34.226:61616,tcp://103.24.34.346:61616,tcp://103.24.34.347:61616"; 
IConnectionFactory factory = new ConnectionFactory(new Uri(brokerUrl));
IConnection connection = factory.CreateConnection("conn1", "conn$34"))

    connection.ClientId = "TESTSUBSCRIBER";
    connection.AcknowledgementMode = AcknowledgementMode.ClientAcknowledge;
    connection.ConnectionInterruptedListener += OnConnectionInturrupted;
    connection.ExceptionListener += OnConnectionExceptionListener;
    connection.ConnectionResumedListener += OnConnectionResumedListener;
    connection.Start();

    ISession session = connection.CreateSession(AcknowledgementMode.ClientAcknowledge);
    var queue = new ActiveMQQueue("VT.TESTSUBSCRIBER.ACCOUNT.UPDATE");
    ActiveMQTopic topic = new ActiveMQTopic();
    IMessageConsumer consumer = session.CreateConsumer(queue); 

    consumer.Listener += OnMessage;



private void OnMessage(IMessage message)
{
    var payload = ((ITextMessage)message).Text;
    Log.Info($"Received message for Client TESTSUBSCRIBER - [{payload}]");
    if(payload != "43342_test")
    {
        message.Acknowledge(); 
            Log.Info($"Message acknowledged for Client TESTSUBSCRIBER - [{payload}]");  
    }
}

private void OnConnectionResumedListener()
{
    Log.Info($"Subscriber connection resumed for Client TESTSUBSCRIBER");
}

private void OnConnectionExceptionListener(Exception exception)
{
    Log.Error(exception);
}

private void OnConnectionInturrupted()
{
    Log.Error($"Subscriber connection interrupted for Client TESTSUBSCRIBER");
}

I am able to publish and subscriber messages. I am running into an issue with one particular case. Lets say the subscriber established connection to the (.225 broker server) from the pool of fail over servers. The publisher published a message. Subscriber received it and it is in the middle of processing. But due to some server patch maintenance, the windows service had to shutdown. As a result the subscriber connection to the broker got disconnected. When windows service came back up, this time subscriber established connection to a different broker server (.346 broker server) from the fail over pool. When that happened, the unacknowledged message never got re-delivered. But If I restart the windows service and by any luck If connection was established to .225 broker (same server to which subscriber was originally connected to), now the subscriber receives the unacknowledged message.

My assumption is that when ActiveMQ is configured in a fail over setup, no matter which broker server from the fail over pool the subscriber is able to establish a connection to, it should always receive the unacknowledged messages.

In some situations fail over setup appears to be working. Lets assume the subscriber was connected to .346 broker server from the fail over pool. The publisher is connected to different broker server (.225 broker) from the same pool and publish a message, subscriber is receiving messages. This proves that Fail over setup is working.

But once a subscriber receives a message from a broker server and if the subscriber is disconnected prior to acknowledging the message, it has to reestablish connection to the same broker server to receive the unacknowledged message. This does not sound right to me.

Is there any additional configuration required on the Active MQ server setup to make this use case work?

Vinod
  • 1,882
  • 2
  • 17
  • 27

1 Answers1

0

The solution to this problem was not on the client side, but rather with the Active MQ server configuration.

For Producer flow control destination policy, add ConditionalNetworkBridgeFilter and enable replayWhenNoConsumers.

Vinod
  • 1,882
  • 2
  • 17
  • 27