JmsTemplate ad hoc consumer is starving - java

I'm trying to create an ad hoc consumer for my JMS messages (I use ActiveMQ)
it looks like this:
jmsTemplate.browse(
q.getName(),
new BrowserCallback<Integer>() {
#Override
public Integer doInJms(Session session, QueueBrowser browser) throws JMSException {
Queue destination = session.createQueue(q.getName());
Enumeration<?> enum1 = browser.getEnumeration();
while (enum1.hasMoreElements()) {
ActiveMQObjectMessage msg = (ActiveMQObjectMessage) enum1.nextElement();
MessageConsumer consumer = session.createConsumer(destination);
Message m = consumer.receiveNoWait();
handle(m);
m.acknowledge();
This ad hoc consumer should handle all the failed to consumed messages.
problem is my original 2-3 consumers that are defined in the spring-messaging.xml are constantly trying to handle the failed events and retries via re-delivery configuration (re delivery delay is set to 3 seconds, and the amount of redeliveries is unlimited)
This consumer should handle these messages but actually is starving (wont recieve these messages at all and therfore
Message m = consumer.receiveNoWait();
returns null all the time.
Here are my beans:
<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<property name="queue" value="*" />
<property name="initialRedeliveryDelay" value="0" />
<property name="redeliveryDelay" value="2000" />
<property name="maximumRedeliveries" value="-1" />
</bean>
<!-- A JmsTemplate instance that uses the cached connection and destination -->
<bean id="redeliveryJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="redeliveryCachingConnectionFactory" />
<property name="messageConverter" ref="eventConverter" />
<property name="sessionTransacted" value="true" />
</bean>
p.s when i change the configuration of p:sessionCacheSize to 1:
<bean id="redeliveryCachingConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="redeliveryConnectionFactory"
p:sessionCacheSize="1" />
It works, but I would like to use the cache.
Any ideas?

You are assuming that queue browser is returning consumable messages. Browsed messages are like a snapshot in time of the moment the browse was done. It will include any messages assigned to a prefetch or by the time you get to it again, it may have been consumed. Additionally you are not waiting around for a message to be assigned, so you are constantly getting in back of the line for messages.
I'd suggest allowing the messages to be moved to a DLQ then allowing this Adhoc consumer to consume from it. Otherwise you are competing with your other consumers for messages.
If you are really dead set against using a DLQ, you can use JMS selectors to consume based on the JMSRedelivered header being true, with a longer wait time. You will still be competing with your other consumers, but would get a message at some point.

Related

having spring integration tcpserver to manage clients and send them messages

I have already created a simple tcp server with spring integration which keeps a connection alive and responses to each request during the connection.
In that requestMethod, I'm also able to read the MessageHeder to get the connectionId.
Now I want to send messages from the server to the client.
As far as i understood the documentation i need to put the connectionid in the MessageHeader and then send the message. But I can't figure out how to do the latter one. I have the Message ready but how do i send/push it out?
Here is my xml-configuration:
<bean id="lfSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer"/>
<int-ip:tcp-connection-factory
id="socketserver"
type="server"
port="30124"
using-nio="true"
deserializer="lfSerializer"
serializer="lfSerializer"
single-use="false"/>
<int-ip:tcp-inbound-channel-adapter id="inboundServer"
channel="inputChannel"
connection-factory="socketserver"/>
<int-ip:tcp-outbound-channel-adapter id="outboundServer"
channel="outputChannel"
connection-factory="socketserver"
/>
<int:channel id="inputChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:channel id="outputChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="logger" level="DEBUG" log-full-message="true"/>
<int:service-activator input-channel="inputChannel"
output-channel="outputChannel"
ref="echoService"
method="test"/>
<bean id="echoService"
class="com.examples.EchoService" />
I also tried to create a bean and another serviceactivator for output, then autowired that bean and called it's "send" method, but I don't know what to implement in that send-method to send out a message.
If it's a simple request/response scenario use an inbound gateway instead of channel adapters and the framework will take care of the correlation for you. This is used in the sample app. Simply have your POJO method return the reply payload.
If you want to send arbitrary messages to the client (i.e. NOT request/reply but, say, in, out, out, in, out, out, out etc) then, yes, you need to build the messages yourself, inserting the ip_connectionId header.
To send them, there are several options:
Inject outputChannel into your code
#Autowired
private MessageChannel outputChannel;
Use a MessagingTemplate to send to the channel (or simply call its send(Message<?> message) method directly).
Or
Use a MessagingGateway with a void return method and inject the gateway into your code.
EDIT:
Note, that if you want to start sending messages before receiving anything, you can obtain the connection id via the connection opened event.

Spring-Integration TCP --> eh-cache chain

I have a Spring-Integration TCP server with request and response and it works correctly. Well now I have to add a new layer to my application.
I have to put my message to an eh-cache db and then send back the ACK. Currently I have only a tcp clients but in the future I will have other sources, as the schema below.
Now the question is:
Can I configure this behavior using Spring-Integration?
I know that I can take the message on my ‘importService’ and put it on my eh-cache writing a code in this way:
public MyMessage handler(MyMessage message) {
try {
myCache.put(mykey, message)
} catch (Exception e) {
logger.error("unable to update" + e);
}
return message;
}
but I think it is not properly correct, and I was just wondering if I can configure my spring configuration file and add another end-point in order to create a chain.
My current config-file is:
<int-ip:tcp-connection-factory id="serverTcpConFact" type="server" port="5566" using-nio="false" single-use="false"
so-receive-buffer-size="8192"
so-send-buffer-size="8192"
so-tcp-no-delay="true"
task-executor="myTaskExecutor"
deserializer="serializer"
serializer="serializer"/>
<int-ip:tcp-inbound-channel-adapter id="tcpInboundAdapter"
channel="tcpInbound"
connection-factory="serverTcpConFact" />
<int:channel id="tcpInbound" />
<int:service-activator
output-channel="tcpOutbound"
input-channel="tcpInbound"
ref="importService"
method="handler" />
<bean id="importService" class="com.MyImportService" />
<int:channel id="tcpOutbound" />
<int-ip:tcp-inbound-gateway id="mygateway"
request-channel="tcpInbound"
reply-channel="tcpOutbound"
reply-timeout="6"/>
<int-ip:tcp-outbound-channel-adapter id="tcpOutboundAdapter"
channel="tcpOutbound"
connection-factory="serverTcpConFact" />
I was looking the public examples but I didn’t find an eh-cache example and a chain example.
Thank you !!
Well, looks like it just enough to move you Cache logic to the ChannelInterceptor:
<int:channel id="tcpInbound">
<int:interceptors>
<bean class="com.my.proj.si.CachePutChannelInterceptor"
</int:interceptors>
</int:channel>
And use this interceptor from any place when you need to use Cache.

Spring intgeration - recipientlistrouter - parallel processing

How does I can achieve parallel processing in spring-integration with recipient-list-router.
My goal is the router has to be content based and sending messages to various channel on parallel processing just like multicast. I tried multicast in Camel with camel-spring-integration but couldn't configure it for content based
Please help if something cane be done
Thanks
If I'm understanding the question right, you just need to use publish subscribe channels as the output channels of the router. The router will direct the message to the right pubsub channel based on content, then all handlers subscribed to that channel will be executed in parallel, assuming the output channel task executor is configured to have multiple threads.
<int:publish-subscribe-channel id="channel1" task-executor="someExecutor"/>
<int:publish-subscribe-channel id="channel2" task-executor="someExecutor"/>
<int:recipient-list-router id="customRouter" input-channel="routingChannel">
<int:recipient channel="channel1" selector-expression="payload.equals('foo')"/>
<int:recipient channel="channel2" selector-expression="headers.containsKey('bar')"/>
</int:recipient-list-router>
The above recipient list router configuration is copied from section 5.1 of the Spring Integration reference manual.
I have achieved similar sort of requirements by extending the Spring-Integrations's RecipientListRouter as follows:
public class CententBasedRecipientListRouter extends RecipientListRouter {
#Override
protected void handleMessageInternal(final Message<?> message) {
......
}
}
in overridden method, you can implement any customized content based routing logic as per your requirements.
This custom router can be configured as follows:
<bean id="customRecipientListRouter" class="CententBasedRecipientListRouter">
<property name="channels">
<list>
<ref bean="parallelProcessingChannel1"/>
<ref bean="parallelProcessingChannel2"/>
<ref bean="parallelProcessingChannel3"/>
</list>
</property>
</bean>
<int:router ref="customRecipientListRouter"
input-channel="routingChannel"
default-output-channel="errorChannel" />
In order to achieve Parallel Processing, you can have Task Executor channels as follows:
<int:channel id="parallelProcessingChannel1">
<int:dispatcher task-executor="threadPoolExecutor"/>
</int:channel>

Asynchronous send to a queue using Spring Jms issue

I have a requirement when I need to write asynchronously to a queue in activemq. I am using Spring Jms to do it. This is the wiring in my spring context file
<bean id="amqProducerConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${activemq.broker}"/>
</bean>
<bean id="pooledProducerConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop" lazy-init="true">
<property name="connectionFactory" ref="amqProducerConnectionFactory" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="pooledProducerConnectionFactory" />
</bean>
And in my code...i do..
void sendMessage(JmsTemplate jmsTemplate, String message, String requestQueue) {
def messageCreator = { session ->
session.createTextMessage(message)
} as MessageCreator
jmsTemplate.send(requestQueue, messageCreator)
}
But the above seems to be working synchronously, not asynchrously. Is there anything that I need to add here that makes the process asynchronous(I mean, App 'A' writes to a queue. It should write to the queue and forget, not wait until App 'B' picks it up from the queue and processes it.)
The JmsTemplate send is never synchronous in terms of waiting for a consumer to take a Message of the Queue in the normal case. The send can however be synchronous in that it waits for a response from the Broker indicating that it has received and stored the Message. This is so that you have an indication of success as Queues must ensure that they are reliable. You can configure many things in the ActiveMQConnectionFactory to control this. Setting the options useAsyncSend will enforce that your send don't wait for a Broker ACK if that is what you want. These options are all documented.
You configure these on the connection URI like so: tcp://localhost:61616?jms.useAsyncSend=true
A send can however block if the ActiveMQ Broker's producer flow control kicks in to prevent a Producer from flooding the Broker with messages. This is configurable as well both in terms of disabling it altogether and also in that you can increase the memory limits on the Broker for when this might kick in.
Finally a Producer send could block if the Connection to the broker is lost and you are using the Failover Transport to have your client automatically reconnect.

Priority with activemq

We're currentyly developping an application using JMS and activemq (5.5.1).
We would like to define a higher priority for some messages, which would make them consumed first.
After setting the producer and the consumer (through spring (3.1) JMSTemplate), the priority does not fully work.
Indeed, when we "turn off" the consumer, and send some messages, the priority is respected, but when we add messages while the consumer is on, the messages are received in the same order they were sent.
The configuration is quite simple:
Priority was activated in the activemq config file:
<policyEntries>
<policyEntry queue=">" prioritizedMessages="true"/>
...
</policyEntries>
And QoS was enabled in the producer template configuration:
<bean id="jmsOCRTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="defaultDestination" ref="destination_ocr" />
<property name="explicitQosEnabled" value="true" />
</bean>
To send a message with a high priority, we just change the template priority property on the producer side:
template.setPriority(9);
Any idea? Is this the normal behaviour, or is there some configuration we would have forgotten?
If my opinion you are not missing anything, I had a similar issue a couple of weeks ago (but with TTL and QPid).
First the JMS is not Strict about this :
JMS does not require that a provider strictly implement priority ordering of messages; however, it should do its best to deliver expedited messages ahead of normal messages.
Second, ActiveMQ does not YET implement priority queues, they say it will somewhere in 6.x version.
So, what you see is actually normal.
As a work-around you can use the Resequencer pattern if it fits your case.
http://camel.apache.org/resequencer.html
Here is another discussion on this subject:
http://activemq.2283324.n4.nabble.com/Priority-message-td2352179.html
I know it is late but this answers may help somebody.
If you want your consumer to consume message based on priority (Priority Queue) then you can use client side message priority. This means, when messages are being sent to your consumer (even before your consumer is receiving them, using prefetch), they will be cached on the consumer side and prioritized by default. This is regardless of whether you’re using priority support on the broker side. This could impact the ordering you see on the consumer so just keep this in mind.
To enable it, set the following configuration option on your broker URL, e.g.,
tcp://0.0.0.0:61616?jms.messagePrioritySupported=true
To disable it, tcp://0.0.0.0:61616?jms.messagePrioritySupported=false
So you do not require to use Camel (if you want to avoid complication)

Categories