how to send email notification while message is delivered to DLQ - jms

how to send email notification while message is delivered to DLQ.
I am doing below code
<spring:beans>
<spring:bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<spring:property name="maximumRedeliveries" value="5" />
<spring:property name="initialRedeliveryDelay" value="500" />
<spring:property name="maximumRedeliveryDelay" value="10000" />
<spring:property name="useExponentialBackOff" value="false" />
<spring:property name="backOffMultiplier" value="3" />
</spring:bean>
<spring:bean id="amqFactory"
class="org.apache.activemq.ActiveMQConnectionFactory" lazy-init="true">
<spring:property name="brokerURL" value="${jms.brokerUrl}" />
<spring:property name="redeliveryPolicy" ref="redeliveryPolicy" />
</spring:bean>
</spring:beans>
<!-- ActiveMQ Connection factory -->
<jms:activemq-connector name="Active_MQ10"
specification="1.1" username="${jms.username}" password="${jms.password}"
brokerURL="${jms.brokerUrl}" validateConnections="true"
persistentDelivery="true" doc:name="Active MQ" connectionFactory-ref="amqFactory"
numberOfConcurrentTransactedReceivers="2">
</jms:activemq-connector>
<jms:endpoint name="delivery-queue-A" connector-ref="Active_MQ10"
queue="delivery-queue-A" doc:name="JMS">
<jms:transaction action="BEGIN_OR_JOIN" />
</jms:endpoint>
How to send email notification we retry fails and message is delivered to DLQ.

Add a rollback exception strategy to your flow:
<rollback-exception-strategy maxRedeliveryAttempts="10">
<on-redelivery-attempts-exceeded>
<set-payload value="Email message body" />
<smtp:outbound-endpoint host="..." port="..." user="yourEmailAddress" password="pass" to="someEmailAddress" from="..." subject="..." responseTimeout="10000" connector-ref="my-mail-connector"/>
<jms:outbound-endpoint queue="dead.letter">
<jms:transaction action="ALWAYS_JOIN" />
</jms:outbound-endpoint>
</on-redelivery-attempts-exceeded>
</rollback-exception-strategy>
More info:
http://www.mulesoft.org/documentation/display/current/Rollback+Exception+Strategy

Related

How to use the RedeliveryPolicy in case of failed messages for outbound->inbound->httpgateway(messages failing here)->EXTERNAL SERVICE

How to use the RedeliveryPolicy in case of failed messages in outbound->inbound->httpoutboundgateway(messages failing here)->external service
the failed messages are not getting retried based on the RedeliveryPolicy mainly because the message is already dequeued before the exception occurs.
<int:channel id="jmsOutChannel" />
<jms:outbound-channel-adapter id="outboundJMSAdaptor" jms-template="jmsTemplate"
channel="jmsOutChannel"
destination-name="#{somebean.queueName}"/>
<int:channel id="jmsInChannel" />
<jms:message-driven-channel-adapter
channel="jmsInChannel" destination-name="#{somebean.queueName}"
connection-factory="jmsConnectionFactory" message-converter="jmsMessageConverter"/>
<int:header-enricher input-channel="jmsInChannel" output-channel="outbound_gateway_channel">
<int:header name="addressId" expression="payload.getId()"/>
<int:header name="Accept-Language" value="en_GB"/>
<int:header name="X-Source-CountryCode" value="GB"/>
<int:header name="X-Source-Operator" value="Enterprise"/>
<int:header name="X-Source-Division" value="CustomerManagement"/>
<int:header name="X-Source-System" value="${sapwebservices.http.header.source.system}"/>
<int:header name="X-Source-Timestamp" expression="new java.text.SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(new java.util.Date())"/>
<int:header name="Accept" value="application/json"/>
<int:header name="Content-Type" value="application/json;charset=UTF-8"/>
</int:header-enricher>
<bean id="httpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="${sapwebservices.http.rest.timeout}"/>
<property name="readTimeout" value="${sapwebservices.http.rest.timeout}"/>
<property name="httpClient" ref="httpClient"/>
</bean>
<int:object-to-json-transformer input-channel="outbound_gateway_channel"
output-channel="outbound_gateway_with_json"
object-mapper="nonNullObjectMapper"/>
<http:outbound-gateway mapped-request-headers="Accept*, Content-Type, X-*, HTTP_REQUEST_HEADERS"
request-channel="outbound_gateway_with_json"
reply-channel="print_payload"
url="${sapwebservices.ws.uri.updatecustomershippingaddress}"
http-method="PUT"
expected-response-type="java.lang.String"
charset="UTF-8"
request-factory="httpRequestFactory">
<http:uri-variable name="id" expression="headers['addressId']"/>
</http:outbound-gateway>
And for the redelivery policy I have,
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="messageConverter" ref="jmsMessageConverter" />
<property name="connectionFactory">
<bean class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory">
<ref local="jmsConnectionFactory" />
</property>
</bean>
</property>
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
<property name="redeliveryPolicy" ref="redeliveryPolicy"/>
<property name="nonBlockingRedelivery" value="true"/>
</bean>
<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<property name="maximumRedeliveries" value="${sapwebservice.redeliveryPolicy.maximumRedeliveries}"/>
<property name="initialRedeliveryDelay" value="${sapwebservice.redeliveryPolicy.initialRedeliveryDelay}"/>
<property name="backOffMultiplier" value="${sapwebservice.redeliveryPolicy.backOffMultiplier}"/>
<property name="useExponentialBackOff" value="${sapwebservice.redeliveryPolicy.useExponentialBackOff}"/>
<property name="redeliveryDelay" value="${sapwebservice.redeliveryPolicy.redeliveryDelay}"/>
</bean>
<bean id="demoQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="demo.queue"/>
</bean>
<bean id="jmsMessageConverter" class="sap.converter.JMSMessageConverter"/>
<amq:broker useJmx="true" persistent="false">
<amq:destinationPolicy>
<amq:policyMap>
<amq:defaultEntry>
<amq:policyEntry queue=">">
<amq:deadLetterStrategy>
<amq:individualDeadLetterStrategy queuePrefix="dlq." useQueueForQueueMessages="true"/>
</amq:deadLetterStrategy>
</amq:policyEntry>
</amq:defaultEntry>
</amq:policyMap>
</amq:destinationPolicy>
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
</amq:broker>
Expected result is to retry based in the RedeliveryPolicy and finally end up in dlq if all the retrials are failed.
Set acknowledge="transacted" on the message-driven channel adapter.
Spring Integration versions 4.2 and later (the current version is 5.1.7) set it to that by default; for earlier versions you have to set it in your configuration so the flow runs in a transaction and the dequeue is rolled back after an exception is thrown.

Spring Integration exception always not reaching errorChannel

<bean id="triggerFileScanner" class="abc.xyz">
<property name="triggerFile" value="value1" />
</bean>
<int-file:inbound-channel-adapter id="fileInbound" directory="somepath/directory" filter="acceptallFilter" scanner="triggerFileScanner"
auto-startup="true" channel="fileChannel">
<int:poller max-messages-per-poll="10" time-unit="SECONDS" fixed-delay="10" receive-timeout="30000" />
</int-file:inbound-channel-adapter>
<int:header-enricher id="headerEnricher" input-channel="fileChannel" output-channel="processChannel">
<int:header name="flowName" value="Name" />
<int:header name="flowID" method="uuidgenerate" ref="headerEnricherBean" />
<int:header name="flowStartTime" method="generateTimeString" ref="headerEnricherBean"></int:header>
<int:header name="fileName" method="deriveFileName" ref="headerEnricherBean" />
</int:header-enricher>
<int:channel id="processChannel">
<int:interceptors>
<int:wire-tap channel="copyChannel" id="copyTap" />
</int:interceptors>
</int:channel>
<int:channel id="copyChannel"></int:channel>
<int-file:outbound-channel-adapter id="fileCopier" channel="copyChannel" delete-source-files="false" filename-generator="dateSuffixFileNameGenerator"
directory="copy.path">
</int-file:outbound-channel-adapter>
<int:filter id="formatcheckFilter" ref="formatValidator" method="validateFile" input-channel="processChannel" output-channel="processDataChannel"
discard-channel="errorChannel" auto-startup="true">
</int:filter>
<int:service-activator id="converter" input-channel="processDataChannel" method="convert" ref="fileToQueryConverter" auto-startup="true"
output-channel="impChannel" />
<bean id="importer" class="testbean.import">
<property name="errorpath" value="path1" />
<property name="sourcepath" value="path2" />
</bean>
<int:service-activator input-channel="impChannel" ref="impeximporter" id="importProcess" method="import" auto-startup="true"
output-channel="archiveChannel" />
<int:channel id="archiveChannel">
<int:interceptors>
<int:wire-tap channel="logChannel" id="completionLogger" />
</int:interceptors>
</int:channel>
<int:channel id="logChannel"></int:channel>
<int-file:outbound-channel-adapter id="fileArchiver" channel="archiveChannel" delete-source-files="true" filename-generator="dateSuffixFileNameGenerator"
directory="archive.path">
</int-file:outbound-channel-adapter>
<int:service-activator id="flowLogger" input-channel="logChannel" ref="messageLogger" method="logMessage">
</int:service-activator>
Sometimes the exceptions from service activator are going to the error channel, however some times they are not going.
I have the error channel defined as below:
<int:channel id="errorChannel" />
<bean id="exceptionHandler" class=my.custom.ExceptionHandler">
</bean>
<int:service-activator id="errorLogger" input-channel="errorChannel" method="handle" ref="exceptionHandler">
</int:service-activator>
I have this error channel being used in many integrations and in my service activators i am just doing a throw Exception("Message")

pass message to producer through jms

How to pass a message to producer(a method defined to sent message to activemq) through spring integration.
Actual requirement is, i need insert data to database and that data to be moved to a queue in activemq,both the operations need to be happened parallely. How can i do it.
<jms:message-driven-channel-adapter id="helloWorldJMSAdapater" destination="helloWorldJMSQueue" connection-factory="jmsConnectionFactory"
channel="postChannel" />
<int:channel id="requestChannel" />
<int:channel id="outputChannel" />
<int-http:inbound-gateway request-channel="requestChannel"
reply-channel="outputChannel" supported-methods="GET" path="/register"
view-name="register">
<int-http:request-mapping />
</int-http:inbound-gateway>
<int-http:inbound-gateway request-channel="postChannel"
reply-channel="outputChannel" supported-methods="POST" path="/registerNew"
error-channel="errorChannel" view-name="login">
</int-http:inbound-gateway>
<int-jdbc:outbound-channel-adapter
query="insert into user_registration (USER_FSTNAME,USER_ADDRESS,USER_STATE,USER_CITY,USER_OCCUPATION,USER_EMAIL,USER_CONTACT,USER_PASSWORD)
values (:fstName,:addrss,:state,:city,:occupation,:email,:contact,:password)"
channel="postChannel" data-source="dataSource" id="sample" sql-parameter-source-factory="spelSource" />
<int:service-activator ref="userService" input-channel="requestChannel"
output-channel="outputChannel" method="message"/>
<bean id="spelSource"
class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<property name="parameterExpressions">
<map>
<entry key="fstName" value="payload[firstName]" />
<entry key="lstName" value="payload[lastName]" />
<entry key="addrss" value="payload[address]" />
<entry key="state" value="payload[state]" />
<entry key="city" value="payload[city]" />
<entry key="occupation" value="payload[occupation]" />
<entry key="email" value="payload[email]"/>
<entry key="contact" value="payload[contact]"/>
<entry key="password" value="payload[password]"/>
</map>
</property>
</bean>
Use a <publish-subscribe-channel/> and subscribe both endpoints to it. They will be executed serially by default, or in parallel if you add a task-executor to the channel.

Spring Integration JMS Issue

We are using Spring Integration to consume messages from a queue and the requirement is to send the message to Error queue if there is any issue in the processing of the message consumed.
Flow works fine but one issue we see is when there is any exception thrown in processing of message, the message is redirected to the Error queue which we have configured but it is appended by the entire stack trace of the exception.
We are looking only for the original message to be delivered to the queue. Below is the configuration we have done,
<bean id="errorQ" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${error.queue}" />
</bean>
<bean id="inQ" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${inbound.queue}" />
</bean>
<int:channel id="error" />
<int:channel id="inbound" />
<int-jms:message-driven-channel-adapter
id="jmsIn" channel="inbound" container="messageListenerContainer"
acknowledge="transacted"></int-jms:message-driven-channel-adapter>
<int-jms:outbound-channel-adapter id="jmsError"
channel="error" connection-factory="mqConnectionFactory"
destination="errorQ" delivery-persistent="true"></int-jms:outbound-channel-adapter>
<int:service-activator id="service"
input-channel="inbound" ref="messageListener" method="someMethodInListerner">
<int:request-handler-advice-chain>
<ref bean="retryWithBackoffAdviceSession" />
</int:request-handler-advice-chain>
<bean id="retryWithBackoffAdviceSession"
class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="${initialInterval}" />
<property name="multiplier" value="${multiplier}" />
<property name="maxInterval" value="${maxInterval}" />
</bean>
</property>
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="${redelivery}" />
</bean>
</property>
</bean>
</property>
<property name="recoveryCallback">
<bean
class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="error" />
</bean>
</property>
</bean>
The message sent to the error is an ErrorMessage with payload MessagingException.
The MessagingException has two properties cause and failedMessage.
So, if you want to send the original failed message to errorQ, you will need to add a transformer to the error flow...
<int:transformer ... expression="payload.failedMessage" />
EDIT
<int:chain input-channel="error">
<int:transformer expression="payload.failedMessage" />
<int-jms:outbound-channel-adapter ... />
</int:chain>
EDIT2
Generally, when using these techniques, it's useful to convey the reason for the failure. You can add the exception's message as a header...
<int:chain input-channel="error">
<int:header-enricher>
<int:header name="failureReason" expression="payload.cause.message" />
</int:header-enricher>
<int:transformer expression="payload.failedMessage" />
<int-jms:outbound-channel-adapter ... />
</int:chain>

Spring Integration queue is not getting message but channel is getting

Using Spring Integration for transferring message from one queue to other in Websphere MQ.
OutPut Channel shows message is going but I am not able to see in Queue from MQ Explorer.How the session commits ? and I am not able to stop the java application. How to gracefully stop with connection stop ?
where I am doing wrong ?
Here is the context config -
<int:logging-channel-adapter log-full-message="true" id="logger" level="INFO"/>
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="localhost" />
<property name="port" value="1414" />
<property name="queueManager" value="TEST" />
<property name="transportType" value="1" />
</bean>
<bean id="inQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="TESTQ" />
</bean>
<bean id="outQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="DEST_QUEUE" />
</bean>
<int:channel id="readFromChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:channel id="sendToChannel" >
<int:queue/>
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int-jms:message-driven-channel-adapter id="jmsInAdapter"
connection-factory="cachingConnectionFactory"
destination="inQueue"
channel="readFromChannel" />
<int-jms:message-driven-channel-adapter id="jmsOutAdapter"
connection-factory="cachingConnectionFactory"
destination="outQueue"
channel="sendToChannel" />
<bean id="myMessenger" class="test.MyMessenger" />
<int:service-activator id="servAct" input-channel="readFromChannel" output-channel="sendToChannel" ref="myMessenger" method="transfer"/>
If I understand your use-case correctly, you want to shift messages from TESTQ to DEST_QUEUE. But you have <int-jms:message-driven-channel-adapter> for both to read messages from them, but no one to put messages to DEST_QUEUE.
Your <int:service-activator> get message from readFromChannel and it means 'get message from TESTQ', but it places message to the sendToChannel. But it doesn't say that you place a message to the DEST_QUEUE.
That is because <int-jms:message-driven-channel-adapter> is for reading messages from JMS (MQ in your case).
To send message to JMS (to the DEST_QUEUE in your case) you have to use <int-jms:outbound-channel-adapter> and there is no reason to mark sendToChannel as <queue>

Resources