Using xa transactions in Karaf - apache-camel

I'm trying to create a xa transaction between postgres (using pax-jdbc to set up xa datasource) and activemq in karaf, using blueprint and camel.
The setup is the following: I have a camel route which receives a jms message, does some database updates, and then sends a jms message to another queue. This other queue then reads the updated records.
The problem is that the second queue is reading the old data instead of getting the updated data.
I believe the cause is that JMS transaction is being "released" first, and the database has not commited the changes yet.
If I put a Thread.sleep(1000) on the second queue, I always read the correct data. Also, I believe the transaction is working fine, if I throw an exception in the camel route, I see no changes in the database, and the jms message does not get sent, proving they are working together.
Here's my blueprint with the jta configs and camel route:
<blueprint
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
xmlns:tx="http://aries.apache.org/xmlns/transactions/v2.0.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://aries.apache.org/xmlns/transactions/v2.0.0 http://aries.apache.org/schemas/transaction/transactionv20.xsd">
<tx:enable/>
<bean id="resourceManager" class="org.apache.activemq.pool.ActiveMQResourceManager" init-method="recoverResource">
<property name="transactionManager" ref="jtaTxManager" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="resourceName" value="activemq.localhost" />
</bean>
<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<property name="maximumRedeliveries" value="0"/>
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<property name="brokerURL" value="$ext{brokerUrl}"/>
<property name="userName" value="karaf"/>
<property name="password" value="karaf"/>
<property name="redeliveryPolicy" ref="redeliveryPolicy"/>
</bean>
<bean id="jmsXaPoolConnectionFactory" class="org.apache.activemq.pool.JcaPooledConnectionFactory">
<property name="name" value="activemq.default"/>
<property name="maxConnections" value="4"/>
<property name="transactionManager" ref="jtaTxManager"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<!-- define the activemq Camel component so we can integrate with the AMQ broker -->
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<!-- due to a bug in activemq-camel we must configure using a nested configuration bean -->
<property name="configuration">
<bean class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsXaPoolConnectionFactory"/>
<!-- JTA transaction manager (Spring interface to Aries-TM) -->
<property name="transactionManager" ref="springJtaTxManager"/>
<!-- IMPORTANT: We set local transactions to false, because the JtaTransactionManager
will take care of enrolling the XA JMS Connection when needed. -->
<property name="transacted" value="false"/>
<!-- IMPORTANT: and disable cache level as the JtaTransactionManager needs to control the consumers
from its JcaPooledConnectionFactory -->
<property name="cacheLevelName" value="CACHE_NONE"/>
</bean>
</property>
</bean>
<reference id="jtaTxManager" interface="org.apache.geronimo.transaction.manager.RecoverableTransactionManager"/>
<reference id="springJtaTxManager" interface="org.springframework.transaction.PlatformTransactionManager"/>
<bean id="required" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
<property name="transactionManager" ref="springJtaTxManager"/>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/blueprint" id="om-bstask-context" useMDCLogging="true">
<route id="notificationConsumer">
<from uri="activemq:queue:incomingNotification"/>
<transacted ref="required"/>
<doTry>
<!-- execute some bd updates -->
<to uri="activemq:anotherQueue"/>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>false</constant>
</handled>
<bean beanType="xxxx.MessagingUtil"
method="logErrorMessage(${headers.JMSXDeliveryCount}, ${headers.om_txid}, 'incomingNotification', ${exception})"/>
</doCatch>
<doFinally>
</doFinally>
</doTry>
</route>
</camelContext>
</blueprint>
Do I have something wrong with my setup? Or what could explain this behavior?
PS I got the config from https://github.com/camelinaction/camelinaction2/blob/master/chapter12/xa-karaf/src/main/resources/OSGI-INF/blueprint/camel-context.xml

Related

Apache Artemis - Apache Camel threaded consumer gets slow over time

I am running Apache Artemis Broker 2.14.0. Below is the consumer connection configuration:
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean class="com.test.CustomProcessBean" id="CustomProcessBean" scope="prototype"/>
<bean id="jmsCF" class="org.apache.qpid.jms.JmsConnectionFactory">
<property name="remoteURI" value="ampq://myhost:5672"/>
</bean>
<bean id="jmsPooledCF" class="org.messaginghub.pooled.jms.JmsPoolConnectionFactory" init-method="start" destroy-method="stop">
<property name="maxConnections" value="3" />
<property name="connectionFactory" ref="jmsCF" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsPooledCF" />
<property name="concurrentConsumers" value="5" />
<property name="maxConcurrentConsumers" value="10" />
</bean>
<bean id="jms" class="org.apache.camel.component.amqp.AMQPComponent">
<property name="configuration" ref="jmsConfig" />
<property name="transacted" value="true" />
</bean>
<bean id="errHandler" class="org.apache.camel.builder.DeadLetterChannelBuilder">
<property name="deadLetterUri" value="jms:queue:customDLQ"/>
<property name="redeliveryPolicy" ref="customRedeliveryPolicyConfig"/>
</bean>
<bean id="customRedeliveryPolicyConfig" class="org.apache.camel.processor.RedeliveryPolicy">
<property name="maximumRedeliveries" value="3"/>
<property name="redeliveryDelay" value="8000"/>
</bean>
<camelContext id="camel"
xmlns="http://camel.apache.org/schema/spring">
<endpoint id="etams" uri="jms:queue:test-queue" />
<route errorHandlerRef="errHandler" >
<from uri="ref:etams"/>
<convertBodyTo type="java.lang.String" />
<threads id="threadedprocess" maxQueueSize="5" poolSize="5" maxPoolSize="5" customId="true" >
<bean ref="CustomProcessBean" method="processMessage"/>
</threads>
</route>
</camelContext>
</beans>
To begin with the route was processing ~100 message-per-second. Over time (~6 hrs) it dropped to ~25 messages-per-second.
From the "Consumers" tab in the Artemis web console I noticed each session is closed and created often.
From the broker side we had provided enough memory 12G. The broker runs with persistence enabled, and the incoming message size are less than 5kb.
Does the Camel threads try to create more session over time? Is this an anti-pattern? Is this the reason for consumer to process the messages slow overtime? When I don't use the Camel threads in the configuration (i.e. just <bean ref="CustomProcessBean ...>) I noticed the session ID created are NOT changing. This might be totally based on the use case, but does re-creating the sessions cause performance stress on broker?
I have faced the same issue and solved it by setting cacheLevelName option in the JMS endpoint to CACHE_CONSUMER. By enabling the transacted option, you end up setting cache level to CACHE_NONE.
This section will explain you better: JMS Component - TRANSACTIONS AND CACHE LEVELS

Camel-JMS hangs every time the linked JMS weblogic server is restarted

Below is what I am trying to achieve:
Pick a file from source directory.
Copy that file into a destination
directory.
Post a message onto a weblogic queue from where a
different application picks the file name and processes it from the
destination directory.
Problem is every time the weblogic server is restarted(due to code deployment), Camel-JMS route hangs and stops working until the Camel route/Servicemix server is restarted.
Below is code for my Camel route:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<!-- file name filter for Outgoing data file from weblogic -->
<bean id="outFilter" class="org.apache.camel.component.file.AntPathMatcherGenericFileFilter">
<property name="includes" value="**/*TEST*.csv"/>
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
<prop key="java.naming.provider.url">t3://<<servername>>:<<serverport>></prop>
<prop key="java.naming.security.principal">admin</prop>
<prop key="java.naming.security.credentials">admin123</prop>
</props>
</property>
</bean>
<bean id="jndiFactoryBean" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="weblogic.jms.ConnectionFactory"/>
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="lookupOnStartup" value="false"/>
<property name="proxyInterface" value="javax.jms.ConnectionFactory"/>
</bean>
<bean id="jndiDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="jndiTemplate"/>
</bean>
<bean id="jmsConfiguration" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jndiFactoryBean"/>
<property name="destinationResolver" ref="jndiDestinationResolver"/>
</bean>
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="configuration" ref="jmsConfiguration" />
</bean>
<!-- Camel Context for WebLogic Environment -->
<camelContext xmlns="http://camel.apache.org/schema/spring" id="weblogic-uat-camelcontext">
<route id="testJMS">
<from uri="file:///C:/input&filter=#outFilter"/>
<log message="File transfer begin"/>
<doTry>
<to uri="file:///C:/output"/>
<setBody>
<simple>${header.CamelFileName}</simple>
</setBody>
<log message="The message contains file name ${body}" />
<to uri="jms:queue:jms/SampleQueue?jmsMessageType=Text"/>
<doCatch>
<exception>java.io.IOException</exception>
<handled>
<constant>false</constant>
</handled>
<log message="{{file.transferFailedMessage}}"/>
</doCatch>
</doTry>
<onCompletion onCompleteOnly="true">
<log message="File transfer complete"/>
</onCompletion>
</route>
</camelContext>
</beans>
Is there a property/configuration in Camel JMS which can be set to handle restarting of JMS server so that camel automatically connects to the weblogic queues every time it is restarted?

Setup independent ActiveMQ broker in camel blueprint xml

I am setting up a ServieMix instance using apache-camel as the routing engine, with my routes defined in a blueprint.xml. I am trying to configure ActiveMQ for my blueprint to be completely isolated from anything else (use its own, private, broker).
Here is my camel blueprint XML
<?xml version="1.0" encoding="UTF-8"?>
<blueprint
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
>
<bean id="record_ip" class="my.service.RecordIP"/>
<bean id="jmsConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://myBroker?create=true&waitForStart=10000" />
<property name="userName" value="shadow"/>
<property name="password" value="broker"/>
</bean>
<bean id="pooledConnectionFactory"
class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="maxConnections" value="8" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsConfig"
class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="concurrentConsumers" value="10"/>
</bean>
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="tracing_route">
<from uri="jetty:http://localhost:9696/trace"/>
<inOnly uri="activemq:queue:ip_capture"/>
</route>
<route id="ip_capture">
<from uri="activemq:queue:ip_capture?concurrentConsumers=1&maxConcurrentConsumers=64&maxMessagesPerTask=100"/>
<bean ref="record_ip"/>
<log message="Finished!" loggingLevel="WARN" />
</route>
</camelContext>
</blueprint>
I don't think it's using the setup at all because I get the following error
Could not refresh JMS Connection for destination 'ip_capture' - retrying in 5000 ms. Cause: Error while attempting to add new Connection to the pool; nested exception is javax.jms.JMSException: Could not create Transport. Reason: java.io.IOException: Broker named 'amq-broker' does not exist.
And amq-broker is the default broker.
I'm pouring through everything I can find but something important is missing
http://camel.apache.org/activemq.html
http://activemq.apache.org/networks-of-brokers.html
http://activemq.apache.org/how-do-i-embed-a-broker-inside-a-connection.html
http://activemq.apache.org/xml-configuration.html
I can't use xmlns:amq="http://activemq.apache.org/schema/core" (ServiceMix can't resolve it)
I am using
ServiceMix 7.0.0
apache-camel/camel-blueprint 2.16.4
activemq-client/camel/blueprint 5.14.3
So long story sort, How do I properly configure ActiveMQ for my blueprint to be completely isolated from anything else?
I ended up not really needing to do this, because for all intents and purposes, the broker is independent, and setting up a new one doesn't change anything.

Problems With Activiti OSGI and Blueprint

i try to use Activiti in KARAF OSGI with camel.
I copied some parts out of the service mix configuration.
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd"
xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0"
xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0"
xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0">
<ext:property-placeholder />
<!--
Setting up the process engine configuration, using an embedded H2 database together with our default Aries
transaction manager.
-->
<bean id="dataSource" class="org.h2.jdbcx.JdbcDataSource">
<property name="URL" value="jdbc:h2:~/activiti"/>
<property name="user" value="sa"/>
<property name="password" value=""/>
</bean>
<reference id="transactionManager" interface="javax.transaction.TransactionManager"/>
<bean id="configuration" class="org.activiti.engine.impl.cfg.JtaProcessEngineConfiguration" ext:field-injection="true">
<property name="databaseType" value="h2"/>
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="true"/>
<property name="transactionsExternallyManaged" value="true" />
<property name="defaultCamelContext" value="defaultContext"/>
</bean>
<!--
Set up the custom resolver implementation to ease integration with Camel routes
-->
<bean id="resolver" class="de.myproject.CamelAwareELResolver"/>
<reference-list availability="optional" interface="org.activiti.camel.ContextProvider">
<reference-listener ref="resolver" bind-method="addContextProvider" unbind-method="removeContextProvider" />
</reference-list>
<reference-list availability="optional" interface="org.activiti.engine.delegate.JavaDelegate">
<reference-listener ref="resolver" bind-method="bindService" unbind-method="unbindService" />
</reference-list>
<!--
Set up the Activiti process engine itself
-->
<bean id="processEngineFactory" class="org.activiti.osgi.blueprint.ProcessEngineFactoryWithELResolver" init-method="init" destroy-method="destroy">
<property name="processEngineConfiguration" ref="configuration"/>
<property name="bundle" ref="blueprintBundle"/>
<property name="blueprintELResolver" ref="resolver" />
</bean>
<bean id="processEngine" factory-ref="processEngineFactory" factory-method="getObject"/>
<bean id="runtimeService" factory-ref="processEngine" factory-method="getRuntimeService" />
<!--
Register the ProcessEngine and RuntimeService as OSGi services to allow other bundles to use them
-->
<service ref="processEngine" interface="org.activiti.engine.ProcessEngine"/>
<service ref="runtimeService" interface="org.activiti.engine.RuntimeService"/>
<bean id="routeBuilder" class="de.myproject.bpmn.BpmnRestRouteBuilder"/>
<camelContext id="clientContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<routeBuilder ref="routeBuilder" />
<route id="entryPointClient">
<from uri="vm:client_queue"/>
<to uri="jobsbpmn://bpmn"/>
</route>
</camelContext>
I can deploy the bundle without problems in the container. When i trigger a workflow with a camel module i get those exception:
2016-11-08 11:56:43,569 | ERROR | m://client_queue | JobsBpmnProducer
| 45 - jobs-logging - 1.0.0 | No Processdefinition found with this
Identifier ActivitiException: Expecting a
SpringProcessEngineConfiguration for the Activiti Camel module.
ClassCastException:
org.activiti.engine.impl.cfg.JtaProcessEngineConfiguration cannot be
cast to org.activiti.spring.SpringProcessEngineConfiguration**
How can i deploy a OSGI conform Processengine using spring to get Camel to work?
This problem might be fixed in the Activity code already.
See https://github.com/Activiti/Activiti/pull/519
Can you try with the newest Activitiy version?

Apache Camel message multiplexer integration pattern

I am trying to determine the best way to combine message streams from two hornetq broker instances into a single stream for processing, using Apache Camel and Spring. This is essentially the opposite of the Camel reciepient list pattern; but instead of one to many I need many to one. One idea is to implement this functionality with the direct component:
<?xml version="1.0" encoding="UTF-8"/>
<beans xmlns="..."
xmlns="...">
<!-- JMS Connection 1 -->
<bean id="jndiTemplate1" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
...Connection 1 Specific Information...
</props>
</property>
</bean>
<bean id="jmsTopicConnectionFactory1"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate1"/>
</property>
<property name="jndiName">
<value>java:jms/RemoteConnectionFactory</value>
</property>
</bean>
<bean id="jms1" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsTopicConnectionFactory1"/>
</bean>
<!-- JMS Connection 2 -->
<bean id="jndiTemplate2" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
...Connection 2 Specific Information...
</props>
</property>
</bean>
<bean id="jmsTopicConnectionFactory2"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate2"/>
</property>
<property name="jndiName">
<value>java:jms/RemoteConnectionFactory</value>
</property>
</bean>
<bean id="jms2" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsTopicConnectionFactory2"/>
</bean>
<!-- Camel route many to 1 using direct component -->
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="hornetQ_broker_1">
<from uri="jms1:topic:testTopic1">
<to uri="direct:process_message">
</route>
<route id="hornetQ_broker_2">
<from uri="jms2:topic:testTopic2">
<to uri="direct:process_message">
</route>
<route id="message_processor">
<from uri="direct:process_message">
<log message="message_processor received message">
</route>
</camelContext>
</beans>
Question: Is the above approach recommended when a many->1 integration pattern is required? If multiple Apache Camel solutions exist, what are the key performance impacts of each approach?
Runtime environment:
HornetQ brokers are JBoss EAP6.
Camel context deployed to FuseSource 4.4.1
Each entity exists on a seperate server/jvm.
Notes:
The hornetQ broker instances cannot be clustered.
The hornetQ broker instances do not contain duplicate data.
I think that your approach is valid for your scenario. However, maybe direct is not the component you need to use for this if you are running in different JVMs.
There are different components for internal queues: Direct, Direct-VM, SEDA, VM, Disruptor... but I believe all of them are if you are running in the JVM (and some of the if you just running in the same CamelContext). For more info: How do the direct, event, seda and vm endpoints compare
If you are going to have different CamelContexts across different JVM will need to use a different component.

Resources