AMQP Prevent automatic message reads - java

I'm using Spring AMQP to listen to messages (configuration has listener-container, service-activator, chain, bridge & aggregators). At application startup AMQP starts reading messages which we don't want. I tried auto-startup=false but it isn't working. Am I missing anything?
Also, if it does work then how do I programmatically start them again? I tried listenerContainer.start();. What about aggregators & others?
EDIT
Following is my config:
<rabbit:queue name="my_queue1" declared-by="consumerAdmin"/>
<rabbit:queue name="my_queue2" declared-by="consumerAdmin"/>
<rabbit:queue name="my_batch1" declared-by="consumerAdmin"/>
<int-amqp:channel id="myPollableChannel" message-driven="false" connection-factory="consumerConnFactory" queue-name="my_queue2"/>
<int-event:inbound-channel-adapter channel="myPollableChannel" auto-startup="false"/>
<int-amqp:channel id="myAggregateChannel" connection-factory="consumerConnFactory"/>
<int-event:inbound-channel-adapter channel="myAggregateChannel" auto-startup="false"/>
<int-amqp:channel id="myChannel" connection-factory="consumerConnFactory"/>
<int-event:inbound-channel-adapter channel="myChannel" auto-startup="false"/>
<int-amqp:channel id="myFailedChannel" connection-factory="consumerConnFactory"/>
<int-event:inbound-channel-adapter channel="myFailedChannel" auto-startup="false"/>
<rabbit:template id="genericTopicTemplateWithRetry" connection-factory="connectionFactory" exchange="my_exchange" retry-template="retryTemplate"/>
<rabbit:topic-exchange name="my_exchange" declared-by="consumerAdmin">
<rabbit:bindings>
<rabbit:binding queue="my_queue1" pattern="pattern1"/>
<rabbit:binding queue="my_queue2" pattern="pattern1"/>
</rabbit:bindings>
</rabbit:topic-exchange>
<int:handler-retry-advice id="retryAdvice" max-attempts="5" recovery-channel="myFailedChannel">
<int:exponential-back-off initial="3000" multiplier="5.0" maximum="300000"/>
</int:handler-retry-advice>
<int:bridge input-channel="myPollableChannel" output-channel="myAggregateChannel">
<int:poller max-messages-per-poll="100" fixed-rate="5000"/>
</int:bridge>
<int:aggregator id="myBatchAggregator"
ref="myAggregator"
correlation-strategy="myCorrelationStrategy"
release-strategy="myReleaseStrategy"
input-channel="myAggregateChannel"
output-channel="myChannel"
expire-groups-upon-completion="true"
send-partial-result-on-expiry="true"
group-timeout="1000" />
<int:chain input-channel="myFailedChannel">
<int:transformer expression="'Failed to publish messages to my channel:' + payload.failedMessage.payload" />
<int-stream:stderr-channel-adapter append-newline="true"/>
</int:chain>
<int:service-activator input-channel="myChannel" output-channel="nullChannel" ref="myWorker" method="myMethod">
<int:request-handler-advice-chain><ref bean="retryAdvice" /></int:request-handler-advice-chain>
</int:service-activator>
<rabbit:listener-container connection-factory="consumerConnFactory" requeue-rejected="false" concurrency="1">
<rabbit:listener ref="myListener" method="listen" queue-names="queues1" admin="consumerAdmin" />
</rabbit:listener-container>

OK. Thank you for the configuration!
Not sure why you need AMQP-bascked channels, but the main issue for you is exactly there.
But pay attention, the <int-amqp:channel> has auto-startup="false" option as well.
And you will be ready to receive data from the AMQP, you will need just start() those channels by their id.

Related

Calling one service activator and another service activator

I have a doubt in Spring Integration Flow. Can we call one int:service-activator after another . Consider below example.
<int:channel id="getPresciption" />
<int:channel id="respPrescription" />
<int-http:inbound-gateway
request-channel="getPresciption" reply-channel="respPrescription"
supported-methods="GET" path="/getAllPresciption">
<int-http:request-mapping
consumes="application/json" produces="application/json" />
</int-http:inbound-gateway>
<int:service-activator
ref="medicineServiceActivator" method="buildPrescription"
input-channel="respPrescription" output-channel="respPrescription" />
<int:service-activator
ref="medicineServiceActivator" method="storePrescription"
input-channel="respPrescription"></int:service-activator>
My Qoestion is can we do this.
or we have to use Aggregator.
You need another channel
<int:service-activator
ref="medicineServiceActivator" method="buildPrescription"
input-channel="respPrescription" output-channel="toStorePrescription" />
<int:service-activator
ref="medicineServiceActivator" method="storePrescription"
input-channel="toStorePrescription"></int:service-activator>

Spring integration gateway routing

I have a problem with spring integration basically I'am trying to create chain which will invoke 1 of several services and returns result as reply to chain gateway for further processing.
<int:chain input-channel="inputChannel" output-channel="outputChannel">
<int:header-enricher>
<int:header name="temporalPayload" expression="payload"/>
<int:header name="matcher" value="other" />
</int:header-enricher>
<int:gateway request-channel="routerChannel" reply-channel="replyChannel" error-channel="errorChannel"/>
<int:transformer expression="headers.temporalPayload"/>
</int:chain>
<int:router input-channel="routerChannel" expression="headers.matcher.matches('(test)|(test2)')?headers.matcher:'other'" >
<int:mapping value="test1" channel="channel1"/>
<int:mapping value="test2" channel="channel2"/>
<int:mapping value="other" channel="channel3" />
</int:router>
<int:service-activator input-channel="channel1" output-channel="replyChannel" ref="service1" method="handle"/>
<int:service-activator input-channel="channel2" output-channel="replyChannel" ref="service2" method="handle"/>
<int:service-activator input-channel="channel3" output-channel="replyChannel" ref="service3" method="handle"/>
Problem that gateway does not receive reply to channel "replyChannel" from service-activator. What I'am doing wrong?
You can turn on DEBUG logging level for org.springframework.integration category and observe how your message travels.
On the other hand, in most cases you don’t need that reply-Channel on the gateway and just rely on the replyChannel header populated by the gateway. In this case you even have to remove the output-Channel on the service-activators.
There might be some subscriber for your repjyChannel who steals messages for the Gateway.
You can try without reply-Channel or investigate logs as I suggested above.

Sending messages with Spring Messaging (Websockets) from a RabbitMQ Listener class

Is it possible to send messages with SimpMessageSendingOperations from a RabbitMQ listener bean?
I have the following listener class:
public class MyJobListener {
#Autowired
public SimpMessageSendingOperations messagingTemplate;
public void handleJob(JobMessage jobMessage) {
doWork(jobMessage);
messagingTemplate.convertAndSend("/topic/greetings", "TEST");
}
}
My Rabbit config file is:
<!-- RabbitMQ configuration -->
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.connection.host}" port="${rabbitmq.connection.port}" />
<rabbit:admin connection-factory="connectionFactory" />
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" />
<!-- Queues -->
<rabbit:queue id="myQueue" name="myQueue" />
<!-- Listeners -->
<bean id="myListener01" class="com.xxx.MyJobListener" />
<bean id="myListener02" class="com.xxx.MyJobListener" />
<bean id="myListener03" class="com.xxx.MyJobListener" />
<bean id="myListener04" class="com.xxx.MyJobListener" />
<rabbit:listener-container connection-factory="connectionFactory" >
<rabbit:listener ref="myListener01" method="handleJob" queue-names="myQueue" />
<rabbit:listener ref="myListener02" method="handleJob" queue-names="myQueue" />
<rabbit:listener ref="myListener03" method="handleJob" queue-names="myQueue" />
<rabbit:listener ref="myListener04" method="handleJob" queue-names="myQueue" />
</rabbit:listener-container>
<!-- Bindings -->
<rabbit:direct-exchange name="directexchange" >
<rabbit:bindings>
<rabbit:binding queue="myQueue"/>
</rabbit:bindings>
</rabbit:direct-exchange>
When message is expected to be sent (messagingTemplate.convertAndSend("/topic/greetings", "TEST")) nothing happens, but if I do the same thing but in a #Controller everything works fine (message is sent through websocket to the browser)
I need to do this to send a notification to the user when the job is finished.
After many tests I changed my rabbit configuration file, leaving only one listener:
<!-- Listeners -->
<bean id="myListener01" class="com.xxx.MyJobListener" />
<rabbit:listener-container connection-factory="connectionFactory" error-handler="queueErrorHandler" >
<rabbit:listener ref="myListener01" method="handleJob" queue-names="myQueue" />
</rabbit:listener-container>
and now it works almost randomly. It's strange, but each 2 calls it works. I mean, two times yes, two times not, two times yes, two times not... and so... It's very strange. I think there is something with the rabbit config...
Definitely is Spring Security configuration. If I disable Spring Security everything works fine. I will find out what it is, and then I'll post the answer here.
I was able to solve it.
The problem was not Spring Security, the problem was I was declarating twice the websocket message broker:
<websocket:message-broker application-destination-prefix="/app" >
<websocket:stomp-endpoint path="/websocket" >
<websocket:sockjs />
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic,/user" />
</websocket:message-broker>
These lines resides in my websocket.xml, and this file was imported more than one time because of an "ugly" import sentences distributions along my .xml spring files.
After ordering these imports and ensuring the bean is only created once everything works fine.
May this helps!

Spring RabbitMQ - xml configuration - manual ack

I have defined configuration for rabbit in spring:
<rabbit:connection-factory id="amqpConnectionFactory" addresses="${amqp.host}:${amqp.port}"
thread-factory="rabbitThreadFactory"
cache-mode="CHANNEL"
channel-cache-size="25"
username="${amqp.user}"
password="${amqp.pass}"
virtual-host="${amqp.vhost}"/>
<rabbit:admin connection-factory="amqpConnectionFactory" id="rabbitAdmin"/>
<rabbit:topic-exchange id="motoTopicExchange" name="moto.ex.topic" >
<rabbit:bindings>
<rabbit:binding pattern="moto.*.speed" queue="motoQueue8"/>
<rabbit:binding pattern="moto.*.tour" queue="motoQueue9"/>
<rabbit:binding pattern="moto.*.naked" queue="motoQueue10"/>
</rabbit:bindings>
</rabbit:topic-exchange>
<rabbit:queue id="motoQueue8" name="moto.queue.8"/>
<rabbit:queue id="motoQueue9" name="moto.queue.9"/>
<rabbit:queue id="motoQueue10" name="moto.queue.10"/>
<rabbit:template id="rabbitTemplate"
connection-factory="amqpConnectionFactory"
retry-template="retryTemplate"
message-converter="rabbitJsonConverter"/>
<bean id="rabbitJsonConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"/>
<rabbit:listener-container connection-factory="amqpConnectionFactory" message-converter="rabbitJsonConverter"
max-concurrency="10" acknowledge="auto">
<rabbit:listener ref="amqpService8" method="handleSimple" queues="motoQueue8"/>
<rabbit:listener ref="amqpService9" method="handleSimple" queues="motoQueue9"/>
<rabbit:listener ref="amqpService10" method="handleSimple" queues="motoQueue10"/>
</rabbit:listener-container>
Where handleSimple method in listeners consumes object for example Motorcycle (there is also json conversion when sending thought amqp).
How could I manually ack massage which was passed into listeners ?
Is it possibleto get MessageHeader alongside object (Motorcycle) ?
I don't want to configure listeners thought annotation.
Thanks
What is the desire for manual acks? It's quite unusual to need them; the container will take care of acking for you.
To use manual acks, you need a ChannelAwareMessageListener implementation.
You would also have to invoke the message converter yourself.

How to pipeline amqp queues with spring integration?

I'm used to camel, where it is somewhat simple to pipeline output from one element to the input of another.
I want to send all application events to an AMQP queue, the fire hose, and then route events to different queues depending on the event type. For example, if the event type is session.created I'd like to take it out from the fire hose and send it to the session.created queue.
I have defined the following raabitmq configuration
<rabbit:connection-factory id="connectionFactory" host="localhost"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
<rabbit:queue name="q.firehose"/>
<rabbit:queue name="q.session.created"/>
<rabbit:direct-exchange name="e.firehose">
<rabbit:bindings>
<rabbit:binding key="firehose" queue="q.firehose"/>
</rabbit:bindings>
</rabbit:direct-exchange>
<rabbit:headers-exchange name="e.router">
<rabbit:bindings>
<rabbit:binding queue="q.session.created">
<rabbit:binding-arguments>
<entry key="x-match" value="all"/>
<entry key="event_type" value="session.created"/>
</rabbit:binding-arguments>
</rabbit:binding>
</rabbit:bindings>
</rabbit:headers-exchange>
And I want to try something like this spring integration configuration:
<int:channel id="fromFirehose"/>
<int:channel id="toRouter"/>
<int-amqp:inbound-channel-adapter channel="fromFirehose" queue-names="q.firehose" connection-factory="connectionFactory"/>
<!-- Some config element here to move all input from the firehose out and put it into e.router--/>
<int-amqp:outbound-channel-adapter channel="toRouter" exchange-name="e.router" amqp-template="routerTemplate" />
Which component is best suited to move input from the fire hose into the e.router exchange? Is this a good approach?
Looks like a transformer can move from messages from one channel to the other but you are obliged to apply a transformation. If there is no other way, is it there a DoNothingTransformer available?
Thanks in advance!
Just link both inbound and outbound adapters to the same channel.
For example:
<int:channel id="fromFirehose"/>
<int-amqp:inbound-channel-adapter channel="fromFirehose" queue-names="q.firehose" connection-factory="connectionFactory"/>
<int-amqp:outbound-channel-adapter channel="fromFirehose" exchange-name="e.router" amqp-template="routerTemplate" />

Categories

Resources