JMS from Synchronous to Asynchronous

2019-09-11 16:39发布

I was able to create a Synchronous service bus using the JMS, but I was not able to turn it to Asynchronous. I'm trying to post a request to a service asynchronously, so if the service is down, I want the JMS queue keeps the request message and when the service starts up it delivers the message to the service and get back the response.

here is my code

<camelContext xmlns="http://camel.apache.org/schema/spring">
        <route >
            <from id ="server" uri="jetty:http://0.0.0.0:9500/rsb/toService?matchOnUriPrefix=true&amp;enableMultipartFilter=false&amp;disableStreamCache=false"/>
            <wireTap uri="log:test?level=INFO"><body><simple>Enter JMS test route and sending message to queue</simple></body></wireTap>
            <!--<to uri="direct:queue"/>-->
            <to uri="jms://testqueue?requestTimeout=360000&amp;replyTo=bar&amp;replyToDeliveryPersistent=true&amp;exchangePattern=InOut&amp;acknowledgementModeName=AUTO_ACKNOWLEDGE"/>
        </route>
        <route id="testqueuelistener" streamCache="true">
            <from uri="jms://testqueue?replyToDeliveryPersistent=true&amp;replyTo=bar" />
            <wireTap uri="log:test?level=INFO"><body><simple>Message recieved from queue: ${body}</simple></body></wireTap>             
            <to uri="http://localhost:18402/Home/addUser?bridgeEndpoint=true&amp;throwExceptionOnFailure=false"/>
            <to uri="jms:service"/> 
        </route>
        <route >
            <from uri="jms:service"/>
            <transform>
                <simple>${body}</simple>
            </transform>
        </route>
    </camelContext>

1条回答
乱世女痞
2楼-- · 2019-09-11 17:18

The issue is that you are accessing the JMS queue without using a transaction - so as soon as you get the message, it's gone from the queue. You need to use a transaction and only commit (or rollback) the message consumption after you've finished processing it.

The relevant Enterprise Integration Pattern is the transactional client. The JMS component documentation also provides some information about transaction. Finally, chapter 9 of Camel in Action (chapter 12 for the second edition) is dedicated to transactions (and I can't recommend it enough!).

You need to:

  • Obtain a JMS transaction manager (which transaction manager you use may depend on your specific use case)
  • Configure the Camel JMS component to use the transaction manager
  • Use a transaction policy to configure the transactional behavior of your route (or just mark the route as transacted, and use the default policy)

The configuration can look something like:

<!-- Import JMS connection factory -->
<osgi:reference id="jmsConnectionPool" interface="javax.jms.ConnectionFactory" />
<!-- We create a Spring JmsTransactionManager (our transaction manager could also be an
imported OSGi service, like we do for the connection factory; for example an XA transaction
manager) -->
<bean id="jmsTxManager" class="org.springframework.jms.connection.JmsTransactionManager">
    <property name="connectionFactory" ref="jmsConnectionPool"/>
</bean>
<!-- We configure the JMS component to use the transaction manager-->
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
    <property name="connectionFactory" ref="jmsConnectionPool" />
    <property name="transacted" value="true"/>
    <property name="transactionManager" ref="jmsTxManager"/>
</bean>

<!-- Here's an example of a transaction policy -->
<bean id="requiresNew" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
    <property name="transactionManager" ref="jtaTransactionManager"/>
    <property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/>
</bean>

Here's a transacted route:

<route id="myRoute">
    <from uri="jms://..." />
    <transacted/>
    ...
</route>

And a route can use a specific transaction policy if we want:

<route id="myRoute">
    <from uri="jms://..." />
    <transacted ref="requiresNew" />
    ...
</route>
查看更多
登录 后发表回答