Keep sending messages in Spring Integration - spring-integration

One module sends messages to the message broker every N second. The other module receive the messages from the broker. The messages is built in a method sendMessage of the service activator. The plan was to use inbound channel adapter (as in the answer) but for some reasons this solution does not work and I keep receiving "Received no Message during the poll, returning 'false'". What is wrong with this configuration?
<int-jms:inbound-channel-adapter id="keepAlivePoller" channel="keepAliveChannel" destination="keepAlive" connection-factory="connectionFactory">
<si:poller id="sendPoller" fixed-rate="${keepalive.sendinterval}" max-messages-per-poll="1"></si:poller>
</int-jms:inbound-channel-adapter>
<si:service-activator input-channel="keepAliveChannel" method="sendMessage" ref="keepAliveSender"/>
<bean class="com.foo.KeepAliveSender"/>
<si:channel id="keepAliveChannel"/>

That will only send a message if there is a message in the "keepAlive" queue.
You can simply use...
<int:inbound-channel-adapter id="keepAlivePoller" channel="keepAliveChannel"
expression="'foo'">
<si:poller id="sendPoller" fixed-rate="${keepalive.sendinterval}" />
</int:inbound-channel-adapter>
... and not use JMS at all.

Related

Spring Integration Poller dropping messages

I want to send the messages received from a jms queue to a spring pub sub channel in order to forward the same message to two destinations. The poller was working fine for a direct channel but is dropping messages when posting to pub sub channel. Please let me know what I am missing.
<int-jms:inbound-channel-adapter connection-factory="connectionFactory" destination-name="queue-name" channel="jmsChannel" extract-payload="false" acknowledge="transacted">
<int:poller max-messages-per-poll="5" fixed-delay="1000"></int:poller>
</int-jms:inbound-channel-adapter>
<int:publish-subscribe-channel id="jmsChannel" task-executor="executor" />
<task:executor id="executor" pool-size="10"/>
<int-jms:outbound-channel-adapter connection-factory="connectionFactory" channel="jmsChannel" destination-name="sample-q" />
The default behavior of a pub/sub channel is similar to a JMS topic with no durable subscriptions; if there are no subscribers, the message is dropped.

Receive the acknowledgement from TCP server to our application using spring Integration

Currently we are using Spring Integration 2.1.0 Release in our application.
Application flow is as below:
Some operation is performed in application and we got the output string in String via Active MQ.
I have used message-driven-channel-adapter and service-activator to read the data from queue.
That data is displayed successfully on Server(application is working as client) using tcp-outbound-gateway.
Problem is while getting the acknowledgement from server.
Created a new channel and entered in reply-channel in tcp-outbound-gateway
Passing the same channel in service-activator as input channel.
It is showing below error:
[task-scheduler-5] 2017-10-05 18:32:20,732 ERROR org.springframework.integration.handler.LoggingHandler - org.springframework.integration.MessageDeliveryException: Dispatcher has no subscribers.
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:108)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:101)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:61)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:128)
at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:149)
Code is as below
<context:property-placeholder />
<!-- Gateway and connection factory setting -->
<int:channel id="telnetLandingChannel" />
<int:channel id="telnetReplyChannel" />
<beans:bean id="clientCustomSerializer"
class="com.telnet.core.serializer.CustomSerializer">
<beans:property name="terminatingChar" value="10" />
<beans:property name="maxLength" value="65535" />
</beans:bean>
<int:gateway id="gw" default-reply-channel="telnetReplyChannel" default-reply-timeout="100000"
service-interface="com.telnet.core.integration.connection.ParseTcpConfiguration$SimpleGateway"
default-request-channel="telnetLandingChannel"/>
<ip:tcp-connection-factory id="clientFactory"
type="client" host="localhost" port="7777" single-use="false" using-nio="false"
serializer="${client.serializer}" deserializer="${client.serializer}" />
<ip:tcp-outbound-gateway id="clientInGw"
request-channel="telnetLandingChannel"
connection-factory="clientFactory"
reply-channel="telnetReplyChannel"
reply-timeout="100000"/>
<!-- To send the messege over server via JMS and serviceActivator -->
<int:channel id="incidentDispatchMessageChannel" />
<int:channel id="jmsChannel" />
<beans:bean id="customClientServiceActivator"
class= "com.telnet.core.integration.CustomClientServiceActivator">
</beans:bean>
<int-jms:message-driven-channel-adapter id="incidentDispatchMessageChannelAdapter" error-channel="errorChannel"
connection-factory="mqConnectionFactory"
destination-name="${incident.processing.messaging.dispatch.queues}"
channel="incidentDispatchMessageChannel"/>
<int:service-activator id="incidentMessageActivator"
input-channel="incidentDispatchMessageChannel"
output-channel="jmsChannel"
ref="customClientServiceActivator" method="getOutboundMessage">
</int:service-activator>
<int:object-to-string-transformer id="clientBytes2String"
input-channel="jmsChannel"
output-channel="telnetLandingChannel"/>
<!-- To receive the acknowledgement message on server via serviceActivator -->
<int:service-activator id="incidentAck"
input-channel="telnetReplyChannel"
ref="customClientServiceActivator" method="getAck">
</int:service-activator>
I have studied various article on stackverFlow but not able to get any solution
Yeah... That isn't clear by the error what channel is guilty.
On the other hand you really use very old Spring Integration version.
Would be great to consider to upgrade to the latest: http://projects.spring.io/spring-integration/.
However I think that issue is somehow around exactly that reply-channel, which you use not only for the <service-activator> but for the <int:gateway> as well.
I suggest you to remove default-reply-channel="telnetReplyChannel" from the gateway definition, remove reply-channel="telnetReplyChannel" from the <ip:tcp-outbound-gateway> definition. And let them communicate via replyChannel header populated by the gateway during request.
Regarding your <int-jms:message-driven-channel-adapter> flow which leads to the same <ip:tcp-outbound-gateway>, I would suggest to still stay with the replyChannel header but here populate it via <header-enricher> before sending message to the telnetLandingChannel. That replyChannel via <header-enricher> would be exactly an input-channel for the subsequent <int:service-activator> to handle ack from the <ip:tcp-outbound-gateway>.
I got the solution of this issue, there are multiple xmls in our code but i have added the code in one to show flow in stackOverflow.
Issue was i had defined in a xml which has only configuration part like Outbound adapter connection factory where as it should be defined in another xml where I am using service activator. Changed the place of channel definition and it worked.
I want to disconnect the TCP (as server) the moment i got the response message. As of now I am using so-timeout, so my TCP server will gets timedout after the time given in so-timeout, but requirement is to disconnect the connection the moment TCP print/display the acknowledgement. Please suggest how can I implement this.

Messages in SpringIntegration

I have QueueChannel with the message-store attribute. Its configuration
<int:channel id="channel1">
<int:queue message-store="msgStore"></int:queue
</int:channel>
Then I want to send messages from channel "channel1" using <int-http:outbound-gateway/>
It looks so:
<int-http:outbound-gateway
url="someUrl"
http-method="PUT"
request-channel="channel1">
<int-http:request-handler-advice-chain>
<int:retry-advice max-attempts="3">
<int:exponential-back-off initial="1000" multiplier="2.0" maximum="8000"/>
</int:retry-advice>
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
My problem:
If the message couldn't be sent, I need that it be in the channel "channel1". But it always is removed from channel.
How do that it remains in the channel?
EDIT1.
<int:poller
default="true"
fixed-rate="100"
receive-timeout="100">
<int:transactional/>
</int:poller>
EDIT2
<int-jdbc:message-store
id="msgStore" data-source="jdbcSQLiteDataSource"/>
Your configuration doesn't look right - you need a poller on the gateway to poll the channel for messages.
Without a transaction, you can't "leave it in the channel" after a failure; you could put it back into the channel with an ExpressionEvaluatingRequestHandlerAdvice (and a flow on its failure channel to transform the error message back to the original), but it will be at the tail of the queue, not the head.
If you message store supports transactions, you can make the poller transactional and the failure will rollback the message into the store.

inbound adapter skipping messages

This is how my configuration looks like
<int-file:inbound-channel-adapter id="files" directory="${lz.dir.${ft}}">
<int:poller fixed-delay="3000" max-messages-per-poll="3" />
</int-file:inbound-channel-adapter>
<int:bridge input-channel="files" output-channel="sourceFiles" />
<int:channel id="sourceFiles">
<int:dispatcher task-executor="executor" />
</int:channel>
<int:service-activator input-channel="sourceFiles"
ref="moveToSource"
method="move" />
<int:aggregator id="filesBuffered"
input-channel="sourceFiles"
output-channel="stagedFiles"
release-strategy-expression="size() == 10"
correlation-strategy-expression="'mes-group'"
expire-groups-upon-completion="true"
/>
<int:channel id="stagedFiles" />
<int:service-activator input-channel="stagedFiles"
ref="moveToStage"
method="move" />
<task:executor id="executor" pool-size="5" queue-capacity="0" rejection-policy="CALLER_RUNS" />
The idea is to poll a directory every 3 second and emit 3 messages per poll to a dispatcher based on channel to allow asynchronous execution. Messages are then aggregated based on number of messages and then emitted to next service activator. The first service activator places files in source directory and second service activator which gets the aggregated list to move those files to staging directory.
What seems to be happening is that source folder skips some files but the staging folder does gets all the files. My guess is that poller sends the messages to the dispatcher channel but when its thread pool gets full it simply ignores the files but somehow the aggregator still gets all the files. Almost like dispatcher channel skips the first service activator step for files it receives after the thread pool limit has reached but those files are still passed to next channel and thats how they still end up getting processed by the second service activator.
What I would like to do is have the poller resend the files that were rejected by the dispatcher. Any ideas would be appreciated.
Thanks
Sorry, I don't understand what you describe, but by your configuration it looks like:
sourceFiles channel is point-to-point one. So, only one subscriber at a time can get message from that channel.
But you have two subscribers - service-activator and aggregator
By default dispatcher uses RoundRobinLoadBalancingStrategy. That means, that first message will be processed by first subscriber, the second one - by second subscriberб and so on, like relay.
So, if you want to have a sequential, there is need to subscribe aggregator to the outbound-channel of moveToSource service-activator and return from move method the same payload. In your case File.
If it isn't your case, so provide, please, correct config or explain your use-case.
Now it is confused, sorry.
HTH

message with no replyTo

The message will not have any replyTo. It just places the message on the queue and does expects any reply "one-way" however if the message processing fails, it needs to be rolled back so that other server could process it. So in-order to process that message I'm using publish-subscribe-channel like below
<int:publish-subscribe-channel id="SplitChannel">
</int:publish-subscribe-channel>
<int-jms:inbound-gateway request-channel="UChannel" request-destination-name="U" extract-request-payload="true" acknowledge="transacted" concurrent-consumers="5" max-messages-per-task="5"/>
<int:chain input-channel="UChannel">
<int-http:outbound-gateway
url="http://localhost/u.php?fileid={fileid}"
http-method="GET"
reply-channel="nullChannel">
<int-http:uri-variable name="fileid" expression="headers.fileid"/>
</int-http:outbound-gateway>
</int:chain>
I'm getting the error as follows
DEBUG: [May-30 00:43:28,768] jms.listener.DefaultMessageListenerContainer - Initiating transaction rollback on application exception
javax.jms.InvalidDestinationException: Cannot determine reply destination: Request message does not contain reply-to destination, and no default reply destination set.
DEBUG: [May-30 00:43:28,768] apache.activemq.ActiveMQSession - 43979-1369895783067-0:15:1 Transaction Rollback
A <gateway/> is for two-way integration; channel adapters are for one-way; use an <int-jms:message-driven-channel-adapter/> instead.

Resources