I am planning to use a buffered queue channel backed by IBM MQ Queue. I would like the Spring message to be put into a MQ Queue so that each can be handled in a separate transaction and if the downstream webservice fails it can be re-tried and ultimately put in a backout queue. This way the messages will never be lost.
I see there are implementations for JDBC Message Store and others but I cannot find anything for MQ Queue. Can you please point me if I am missing
<si:service-activator id="eventHandler"
input-channel="channel1l" output-channel="amountDataChannel"
method="processEvent" ref="eventService" >
</si:service-activator>
<si:channel id="amountDataChannel">
<si:queue message-store="queueMessageStore ???"/>
</si:channel>
<si:chain id="dataChain1" input-channel="amountDataChannel" output-
channel="outputChannel">
<si:poller fixed-rate="10000" max-messages-per-poll="1" />
<si:transformer ref="transformer" method="transformEvent"/>
..Make webservice call
</si:chain>
Update
After reading through the documentation here is what I am doing though I have a question on transaction manger Should I be giving the transaction-manager which I declared or will it automatically participate using acknowldege attribute. If yes then what is the difference in both of them?
<jee:jndi-lookup id="amountQueue" jndi-name="jms/amountQueue" />
<si-jms:channel id="amountDataChannel" queue="amountQueue" connection-
factory="queueConnectionFactory" transaction-manager="txManager" />
Also for production ready is there any other attribute which needs to be given ?
Appreciate your help on this
Please refer to the JMS section of the documentation for JMS-backed Channels.
Related
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.
I have issue with reply-timeout property of StoredProcOutboundGateway in spring integration. I have gone through the documentation and it says reply-time out will not work in case of direct channel for the Gateway . But in case of external integration gateways ie StoredProcOutboundGateway it says
"when sending to a DirectChannel, the invocation will occur in the sender’s thread so the failing of the send operation may be caused by other components further downstream "
As per my design my StoredProcOutboundGateway reply is sending to a Direct channel.Will the StoredProcOutboundGateway throw exception after the reply-time out expiration ? .For re creating this scenario I have put a debug point and wait for configured reply time out in the first line of StoredProcOutboundGateway.handleRequestMessage method ,But it didn't thrown any exception and it returned successsful response even after configured time .
<int:gateway id="idGateway" service-interface="Gateway">
<int:method name="getStoreProcData" request-channel="store.req.channel" reply-channel="store.reply.channel" />
</int:gateway>
<int-jdbc:stored-proc-outbound-gateway stored-procedure-name="GE_PKG.GET_PRC"
ignore-column-meta-data="true" reply-timeout="2000" request-channel="store.req.channel" reply-channel="store.reply.channel" is-function="false"
............other cursor config
</int-jdbc:stored-proc-outbound-gateway>enter code here
<int:channel id="store.req.channel" />
<int:channel id="store.reply.channel" />
Spring-Integration V4..1.2 DB oracle ojdbc6
The reply-timeout only applies if the reply-channel can block - such as a bounded QueueChannel that is full.
i.e. it is a timeout for the send to the reply-channel.
It will never occur with a DirectChannel.
I have an integration application that mostly works, but noticed yesterday a message was lost. At the time, the service-activator endpoint was extremely busy processing a previous message.
Basically, my integration flow is:
jdbc:inbound-channel-adapter --> splitter -> aggregator (based on a type field) -> [pollable channel] --> service-activator
From the log, I can see a group of messages polled, split, aggregated, expired (via a message store reaper), and placed on the creation channel. There is a preSend and postSend event in the log for placing the message on the creationChannel, but that's the end of it. It never gets to my service-activator, there's no messages in the jdbc message store and I dont see any errors.
Could there an issue with how I have either the service-activator or poller configured (or a combination)?
Here is the configuration applicable to the issue.
<int:poller default="true" fixed-delay="1000" receive-timeout="0" />
<int-jdbc:message-store id="jdbc-messageStore" data-source="dataSource" />
<int:channel id="creationChannel" >
<int:queue message-store="jdbc-messageStore" />
</int:channel>
<!-- Endpoint responsible for creating Archive from List of Document objects -->
<bean id="archiveCreator" class="org.abc.ArchiveCreator"/>
<int:service-activator ref="archiveCreator" method="createArchive" input-channel="creationChannel" />
First of all you should mark your <poller> as <transactional>.
Another point switch on the org.springframework.integration DEBUG logging level and show here the log, when a message is lost.
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
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.