Apache Camel message multiplexer integration pattern - apache-camel

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.

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

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.

ActiveMQ with Camel basics

I already googled for a while looking for step by step tutorials explaining setup and integration of ActiveMQ with Camel, but had little success to find a basic tutorial.
I already have a running and configured ActiveMQ server but I just can't get the Camel Component up and running. It always creates a separate broker and I just can't make Camel connect to the existing broker instance.
Any hints where I can find basic tutorials on how to integrate Camel and develop a better understanding on how those two work together?
Please do not refere to Camel-Website, as this along with the docs for ActiveMQ where my primary source to fight through the stuff, but it helped only a little on setup, configuration and through understanding of both packages.
Thanks
Following is configuration of Active MQ with camel.
<bean id="jmsConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</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/spring">
<route id="*****">
<from uri="+++++++++" />
<choice>
<to uri="activemq:queue:**********"/>
</choice>
</route>
</camelContext>
You can consider some of the Camel books which has extensive information about all sorts of stuff with Camel, also how to use it with JMS and AMQ.
http://camel.apache.org/books
And there is some examples from AMQ you can look at as well: https://github.com/apache/camel/tree/master/examples
And you can try to find some 3rd party blogs or articles that cover AMQ with Camel: http://camel.apache.org/articles
And recently there was this article about AMQ with Camel:
http://www.puretechy.com/blog/apache-camel-activemq-example

Using xa transactions in Karaf

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

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?

Resources