Durable subscriber with JMS Connector Alpakka - jms

Using Alpakka, we can create a non-durable subscriber for any topic using the below code:
Source<String, NotUsed> jmsTopicSource = JmsSource
.textSource(JmsSourceSettings
.create(connectionFactory)
.withTopic("topic")
.withBufferSize(10)
);
Does anyone have an idea how to make this topic subscriber durable?

I don't think the creation of durable consumers is supported in Alpakka's JMS connector, as of version 0.9. In the internal API, JmsConnector is calling Session#createConsumer:
private[jms] def createConsumer()(implicit ec: ExecutionContext): Future[jms.MessageConsumer] =
Future {
session.createConsumer(destination)
}
There doesn't appear to be a way to invoke any of the methods (e.g., Session#createDurableConsumer) that the JMS Session object provides to create durable consumers.

Related

JMSListener escapes '.' for durable subscriptions

With Spring JMS 4.3.19 as well as with 5.2.5 I am trying to set up a JMSListener for durable subscriptions:
#JmsListener(destination = "test", subscription = "Consumer.Test", connectionFactory = "factory")
public void receiveFromDurableSub(String message) {
System.out.println("receiveFromTest: " + message);
}
But it ends up in Consumer\\.Test. For addresses it works somehow.
How can I avoid those backslashes?
JMS topic subscriptions are implemented on ActiveMQ Artemis as queues. Each subscription gets it own queue.
The name of the queue depends on how the subscription is configured. The broker will take the JMS client ID (if one is configured), the JMS subscription name (if one is configured), and the JMS subscription's durability to construct the name of the underlying subscription queue. The broker uses the . character to concatenate all these piece of information together to compose the final name. See the related source code for more details on that bit.
In order to be able to decompose this name into its constituent parts later any uses of the . character in the client ID or subscription name have to be escaped.
Since you're using Consumer.Test for the JMS subscription's name this will ultimately be escaped to Consumer\\.Test for use in the underlying subscription queue's name. The broker's use of the . character is not configurable in this case.
If you don't want your subscription's name to be escaped then I recommend you don't use a name with a . character in it (e.g. Consumer-Test).

Can we make JMS Producer to use "AmazonSQSAsyncClient" 's method "sendMessageAsync" to send the message?

I have a JMS producer which is using the AmazonSQSClient's sendMessage method to produce the message. I want to use the AmazonSQSAsyncClient's sendMessageAsync method in my JMS producer. How can I achieve that?
Obtain the AmazonSQSAsync client. In spring boot you can just Autowire it.
Now as you can see the sendMessageAsync returns a Future, so you need to wait for it.
amazonSQSAsync.sendMessageAsync("logical queue name", "message").get(10, TimeUnit.SECONDS)
If you prefer you can also use the other method:
amazonSQSAsync.sendMessage("logical queue name", "message")
It won't return Future but it will timeout if the receive timeout is reached.

Redelivery of JMS message in microserices

I want to know the redelivery of JMS in a microservices.
For example, if I have a microservices system. And I have 2 instances of User service. And have a listener on a destination in user service. It means I have 2 listeners. The listener is like this:
#JmsListener(destination = "order:new", containerFactory = "orderFactory")
#Transactional
public void create(OrderDTO orderDTO) {
Order order = new Order(orderDTO);
orderRepository.save(order);
jmsTemplate.convertAndSend("order:need_to_pay", order);
}
So my question is, how many times a message will be delivered. And if there is some error in this function, and the message will be re-delivered. But I have 2 instances of the service. And on which this message will be delivered?
It's not part of the spec; it depends on the broker configuration how many times it will be delivered; many brokers can be configured to send the message to a dead-letter queue after some number of attempts.
There is no guarantee the redelivery will go to the same instance.

Webpshere MQ temporary dynamic queues using Model queues

I am using the following sample code to create a temporary replyto queue
final TemporaryQueue replyQueue = session.createTemporaryQueue();
message.setJMSReplyTo(replyQueue);
producer.send(destination, message);
This uses a default model queue SYSTEM.DEFAULT.MODEL.QUEUE to create the temporary dynamic queue.
Please just want to know if there is way to use my own model queue instead of using the default model queue.
Thanks
Check the JavaDoc for the MQConnectionFactory - there's a model queue property on the connection factory that controls this.
http://www-01.ibm.com/support/knowledgecenter/api/content/SSFKSJ_8.0.0/com.ibm.mq.javadoc.doc/WMQJMSClasses/index.html

Is it possible for a JMS topic to have multiple publishers

From what I've read so-far, a JMS Topic is 1-to-Many and I wonder if its possible to support Many-to-Many using a topic. Consider a topic called "Reports" with multiple services spread out across an enterprise needing to publish scheduled reports. Having multiple publishers would alleviate the need to subscribe interested applications to a topic for each of the reporting services.
Note:
I'm going to use Spring and ActiveMQ in my solution.
#Mondain: yes, very much possible. A practical example would be live stock market price feed provided by multiple sources and those feed consumed by multiple channels.
Yes, you can create many TopicPublisher from your TopicSession, and many applications can connect the same Topic using TopicPublisher or TopicSubscriber.
You can do something like this, and call CreateMessageProducer to create a new instance of producer anywhere in your application.
public ActiveMqProducer(string activeMqServiceUrl)
{
_activeMqServiceUrl = activeMqServiceUrl;
IConnectionFactory factory = new ConnectionFactory(new Uri(_activeMqServiceUrl));
_activeMqConnection = factory.CreateConnection();
_activeMqSession = _activeMqConnection.CreateSession(AcknowledgementMode.Transactional);
_activeMqConnection.Start();
}
private IMessageProducer CreateMessageProducer(string mqTopicName)
{
ITopic destination = SessionUtil.GetTopic(_activeMqSession, mqTopicName);
var producer = _activeMqSession.CreateProducer(destination);
return producer;
}

Resources