camel-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Raul Kripalani <r...@fusesource.com>
Subject Re: OSGI Transaction Propagation to Camel Route
Date Tue, 17 Apr 2012 08:47:55 GMT
Hi Chris!

Transaction Managers bind transactions to threads, and a possible cause for
your transaction getting lost is that your route is being called
asynchronously from another thread.

This is because you are using ProducerTemplate.send...().

Can you replace this with ProducerTemplate.requestBodyAndHeader(...), which
in theory should call the route synchronously in the same thread?

Regards,

*Raúl Kripalani*
Principal Consultant | FuseSource Corp.
raul@fusesource.com | fusesource.com <http://www.fusesource.com/> skype:
raul.fuse | twitter: @raulvk <http://twitter.com/raulvk>,
@fusenews<http://twitter.com/fusenews>

<http://twitter.com/fusenews>

On 16 April 2012 23:09, Chris Geer <chris@cxtsoftware.com> wrote:

> Claus,
>
> I'm still struggling with this so I've put together a quick sample project
> that shows the problem. It consists of an OSGI component that runs under a
> transaction and posts two JMS messages (one with Camel and one with JMS
> APIs) then rolls back the transactions. I would hope to see both messages
> not be delivered but instead what I see if the one sent via camel being
> delivered while the other one is rolled back. I'm sure I'm probably doing
> something wrong but I can't figure it out.
>
> Is there a place I can post my sample project where someone might be able
> to give it a quick look?
>
> Thanks,
> Chris
>
> On Sat, Apr 7, 2012 at 3:19 AM, Claus Ibsen <claus.ibsen@gmail.com> wrote:
>
> > On Thu, Apr 5, 2012 at 5:57 PM, Chris Geer <chris@cxtsoftware.com>
> wrote:
> > > Claus,
> > >
> > > I realize that but I can't explain what I'm seeing. Here is an
> additional
> > > piece of info, here is debug log for the sending of the message. As you
> > can
> > > see, the transaction fields are all null but I don't know if that is
> > normal
> > > or a symptom of the problem.
> > >
> > > 08:51:22,906 | DEBUG | erations/address | JmsConfiguration
> > > | 169 - org.apache.camel.camel-jms - 2.9.2.SNAPSHOT | Sending JMS
> message
> > > to: topic://event-notifications with message: ActiveMQBytesMessage
> > > {commandId = 0, responseRequired = false, messageId = null,
> > > originalDestination = null, originalTransactionId = null, producerId =
> > > null, destination = null, transactionId = null, expiration = 0,
> > timestamp =
> > > 0, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId =
> > null,
> > > replyTo = null, persistent = true, type = null, priority = 0, groupID =
> > > null, groupSequence = 0, targetConsumerId = null, compressed = false,
> > > userID = null, content = null, marshalledProperties = null,
> > dataStructure =
> > > null, redeliveryCounter = 0, size = 0, properties =
> {EntityType=Address,
> > > breadcrumbId=ID-CXTMBP-Chris-local-62052-1333577461603-22-3,
> > > EventType=EntityCreated, ClientID=0}, readOnlyProperties = false,
> > > readOnlyBody = false, droppable = false} ActiveMQBytesMessage{
> bytesOut =
> > > org.apache.activemq.util.ByteArrayOutputStream@51762faf, dataOut =
> > > java.io.DataOutputStream@2634b3f1, dataIn = null }
> > >
> >
> > I would only suspect transaction ids being populated in the AMQ
> > message if the message originated from the AMQ broker. Creating a new
> > message to be send would most likely not populate TX ids and whatnot.
> > But the work is still carried out under the TX manager. (if TX is
> > properly configured and working - yeah thats the hard part).
> >
> > > Here is more of the stack trace that shows the transaction being
> > committed
> > > for some reason.
> > >
> > > 08:51:22,888 | DEBUG | erations/address | TransactionErrorHandler
> > >  | 166 - org.apache.camel.camel-core - 2.9.2.SNAPSHOT | Transaction
> begin
> > > (0x1f2198ab) redelivered(unknown) for (MessageId:
> > > ID-CXTMBP-Chris-local-62052-1333577461603-22-3 on ExchangeId:
> > > ID-CXTMBP-Chris-local-62052-1333577461603-22-4))
> > > 08:51:22,888 | DEBUG | erations/address | JtaTransactionManager
> > >  | 139 - org.springframework.transaction - 3.0.6.RELEASE |
> Participating
> > in
> > > existing transaction
> > > 08:51:22,906 | DEBUG | erations/address | JmsConfiguration
> > > | 169 - org.apache.camel.camel-jms - 2.9.2.SNAPSHOT | Sending JMS
> message
> > > to: topic://event-notifications with message: ActiveMQBytesMessage
> > > {commandId = 0, responseRequired = false, messageId = null,
> > > originalDestination = null, originalTransactionId = null, producerId =
> > > null, destination = null, transactionId = null, expiration = 0,
> > timestamp =
> > > 0, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId =
> > null,
> > > replyTo = null, persistent = true, type = null, priority = 0, groupID =
> > > null, groupSequence = 0, targetConsumerId = null, compressed = false,
> > > userID = null, content = null, marshalledProperties = null,
> > dataStructure =
> > > null, redeliveryCounter = 0, size = 0, properties =
> {EntityType=Address,
> > > breadcrumbId=ID-CXTMBP-Chris-local-62052-1333577461603-22-3,
> > > EventType=EntityCreated, ClientID=0}, readOnlyProperties = false,
> > > readOnlyBody = false, droppable = false} ActiveMQBytesMessage{
> bytesOut =
> > > org.apache.activemq.util.ByteArrayOutputStream@51762faf, dataOut =
> > > java.io.DataOutputStream@2634b3f1, dataIn = null }
> > > 08:51:22,907 | DEBUG | erations/address | JtaTransactionManager
> > >  | 139 - org.springframework.transaction - 3.0.6.RELEASE | Registering
> > > after-completion synchronization with existing JTA transaction
> > > 08:51:22,907 | DEBUG | erations/address | TransactionErrorHandler
> > >  | 166 - org.apache.camel.camel-core - 2.9.2.SNAPSHOT | Transaction
> > commit
> > > (0x1f2198ab) redelivered(unknown) for (MessageId:
> > > ID-CXTMBP-Chris-local-62052-1333577461603-22-3 on ExchangeId:
> > > ID-CXTMBP-Chris-local-62052-1333577461603-22-4))
> > >
> >
> > That last debug logging is just Camel saying that the TX completed
> > successfully (in that leg). Its up to the TX manager when actually to
> > commit the TX. If a TX was started outside, then the commit is
> > executed at that point.
> >
> > So this is normal.
> >
> > > On Thu, Apr 5, 2012 at 8:19 AM, Claus Ibsen <claus.ibsen@gmail.com>
> > wrote:
> > >
> > >> On Thu, Apr 5, 2012 at 4:59 PM, Chris Geer <chris@cxtsoftware.com>
> > wrote:
> > >> > Christian,
> > >> >
> > >> > I have that book and that is what I used for a lot of my reference.
> In
> > >> > fact, they only major difference between his source and mine is he
> is
> > >> using
> > >> > Atomikos as the transaction manager and I'm using aries. I am
> > referencing
> > >> > an existing PlatformTransactionManager instead of creating a
> > >> > JtaTransactionManager but PlatformTransactionManager implements
> > >> > JtaTransactionManager so it should be ok.
> > >> >
> > >> > As for the datasource, I'm actually publishing it from another OSGI
> > >> > component as a service so it can be reused. I'm creating it in code
> > right
> > >> > now as defined below.
> > >> >
> > >> >        BasicManagedDataSource ds = new BasicManagedDataSource();
> > >> >
> > >> >        if(xaDataSourceClass != null &&
> !xaDataSourceClass.isEmpty()) {
> > >> >            try {
> > >> >                XADataSource dsi =
> > >> > (XADataSource)Class.forName(xaDataSourceClass).newInstance();
> > >> >                Method setUrl = dsi.getClass().getMethod("setUrl",
> new
> > >> > Class[] {String.class});
> > >> >                setUrl.invoke(dsi, (String) config.get(CONNSTR_KEY));
> > >> >                ds.setXADataSource(xaDataSourceClass);
> > >> >                ds.setXaDataSourceInstance(dsi);
> > >> >            } catch (IllegalArgumentException ex) {
> > >> >                throw new ConfigurationException("xaDataSourceClass",
> > >> > "Couldn't create instance", ex);
> > >> >            } catch (InvocationTargetException ex) {
> > >> >                throw new ConfigurationException("xaDataSourceClass",
> > >> > "Couldn't create instance", ex);
> > >> >            } catch (NoSuchMethodException ex) {
> > >> >                throw new ConfigurationException("xaDataSourceClass",
> > >> > "Couldn't create instance", ex);
> > >> >            } catch (SecurityException ex) {
> > >> >                throw new ConfigurationException("xaDataSourceClass",
> > >> > "Couldn't create instance", ex);
> > >> >            } catch (InstantiationException ex) {
> > >> >                throw new ConfigurationException("xaDataSourceClass",
> > >> > "Couldn't create instance", ex);
> > >> >            } catch (IllegalAccessException ex) {
> > >> >                throw new ConfigurationException("xaDataSourceClass",
> > >> > "Couldn't create instance", ex);
> > >> >            } catch (ClassNotFoundException ex) {
> > >> >                throw new ConfigurationException("xaDataSourceClass",
> > >> > "Class not found", ex);
> > >> >            }
> > >> >        } else {
> > >> >            ds.setDriverClassName((String) config.get(DRIVER_KEY));
> > >> >            ds.setUrl((String) config.get(CONNSTR_KEY));
> > >> >        }
> > >> >
> > >> >        BundleContext context =
> > >> >
> > >>
> >
> FrameworkUtil.getBundle(BedrockConnectionPoolFactory.class).getBundleContext();
> > >> >
> > >> >        ds.setTransactionManager(transMgr);
> > >> >
> > >> >        Hashtable<String, String> sp = new Hashtable<String,
> String>();
> > >> >        sp.put(DSNAME_KEY, (String) config.get(DSNAME_KEY));
> > >> >        ServiceRegistration reg =
> > >> > context.registerService("javax.sql.XADataSource",
> > >> > ds.getXaDataSourceInstance(), sp);
> > >> >        regMap.put(id, reg);
> > >> >
> > >> > The transMgr variable above is looking up the Aries transaction
> > manager
> > >> > deployed in SMX (same one my JMS code is getting through the
> > >> > PlatformTransactionManager interface).
> > >> >
> > >> > The biggest challenge I've had is that every single camel
> transaction
> > >> > example I've seen starts the transaction INSIDE camel. They all
> > resemble
> > >> > the diagram on page 300 of Claus' book. I haven't seen any example
> > where
> > >> > camel is enlisted in an already existing transaction. I was hoping
> > that
> > >> was
> > >> > just because examples are traditionally simple but maybe it wasn't
> > >> designed
> > >> > to do that?
> > >> >
> > >>
> > >> Camel does not have its own TX manager etc. All we do is to hook into
> > >> the Spring TX manager.
> > >> So if there is already a TX in progress, then Camel should just play
> > >> along, and run in that same TX.
> > >>
> > >> The Camel processing occurs in a Spring TX template in its -
> > >> doInTransaction method. That happens when you use the <transacted>
in
> > >> the Route.
> > >>
> > >> > Chris
> > >> >
> > >> > On Thu, Apr 5, 2012 at 1:11 AM, Christian Müller <
> > >> > christian.mueller@gmail.com> wrote:
> > >> >
> > >> >> Chris,
> > >> >> may be the source code of Claus book "Camel in Action" is helpful
> for
> > >> you
> > >> >> [1].
> > >> >>
> > >> >> Could you als share your datasource configuration with us? It
was
> > not in
> > >> >> your post...
> > >> >>
> > >> >> [1]
> > >> >>
> > >> >>
> > >>
> >
> http://code.google.com/p/camelinaction/source/browse/trunk/chapter9/xa/src/test/resources/spring-context.xml
> > >> >>
> > >> >> Best,
> > >> >> Christian
> > >> >>
> > >> >> On Thu, Apr 5, 2012 at 7:13 AM, Chris Geer <chris@cxtsoftware.com>
> > >> wrote:
> > >> >>
> > >> >> > We are building an application using ServiceMix (CXF, Camel,
> > Karaf...)
> > >> >> and
> > >> >> > we've run into an issue with transactions not propagating
to
> camel
> > >> routes
> > >> >> > as we'd like them to. We have several OSGI components that
run
> > under
> > >> >> > transactions using the Aries transaction management like
the
> > >> following:
> > >> >> >
> > >> >> >     <bean id="serviceBean" class="<class>">
> > >> >> >        <property name="dataSource" ref="ds"/>
> > >> >> >        <property name="camelContext" ref="camelCtx"/>
> > >> >> >        <tx:transaction method="updateAddress, createAddress,
> > >> >> > deleteAddress" value="Required" />
> > >> >> >        <tx:transaction method="getAddress, findAddresses"
> > >> >> value="Supports"
> > >> >> > />
> > >> >> >    </bean>
> > >> >> >
> > >> >> > We have published a DataSource which is transaction aware
for our
> > >> >> > components to use. It shows up in SMX as the following:
> > >> >> >
> > >> >> > aries.xa.aware = true
> > >> >> > dsName = ds
> > >> >> > objectClass = javax.sql.DataSource
> > >> >> > service.id = 298
> > >> >> >
> > >> >> > In our components we are able to perform database transactions
> that
> > >> >> > successfully get committed/rolled back as expected without
having
> > to
> > >> >> > manually enlist the JDBC connection. It works great. Those
same
> > >> >> components
> > >> >> > also will send various JMS messages as they succeed/fail.
Our
> goal
> > is
> > >> >> that
> > >> >> > if a component sends a JMS message on success and later rolls
> back
> > the
> > >> >> JMS
> > >> >> > message would be retracted. If we lookup a JMS ConnectionFactory,
> > >> create
> > >> >> a
> > >> >> > connection, session, manually enlist the session into the
current
> > >> >> > transaction and send the message all in code it actually
works as
> > >> >> desired.
> > >> >> >
> > >> >> > What we hope to be able to do however is to remove the code
and
> use
> > >> camel
> > >> >> > instead to process the message and pass it along to the JMS
> topic,
> > in
> > >> the
> > >> >> > same transaction that the OSGI component is running in but
we
> can't
> > >> quite
> > >> >> > get it to work. Below is our latest configuration and code
and at
> > this
> > >> >> > point the message posts to the topic but never rolls back.
> > >> >> >
> > >> >> > Blueprint File
> > >> >> >    <bean id="activemq"
> > >> >> > class="org.apache.activemq.camel.component.ActiveMQComponent">
> > >> >> >        <property name="connectionFactory"
> > >> ref="jmsXaConnectionFactory"/>
> > >> >> >        <property name="transacted" value="true"/>
> > >> >> >        <property name="transactionManager"
> > >> ref="jmsTransactionManager"/>
> > >> >> >    </bean>
> > >> >> >
> > >> >> >    <bean id="mandatory"
> > >> >> > class="org.apache.camel.spring.spi.SpringTransactionPolicy">
> > >> >> >        <property name="transactionManager"
> > >> ref="jmsTransactionManager"/>
> > >> >> >        <property name="propagationBehaviorName"
> > >> >> > value="PROPAGATION_MANDATORY"/>
> > >> >> >    </bean>
> > >> >> >
> > >> >> >    <bean id="jmsXaConnectionFactory"
> > >> >> >          class="org.apache.activemq.ActiveMQXAConnectionFactory">
> > >> >> >        <property name="brokerURL" value="tcp://localhost:61616"/>
> > >> >> >    </bean>
> > >> >> >
> > >> >> >    <reference id="jmsTransactionManager"
> > >> >> >
> > >>
> interface="org.springframework.transaction.PlatformTransactionManager"/>
> > >> >> >
> > >> >> >
> > >> >> >    <camel:camelContext id="camelCtx" trace="true">
> > >> >> >        <camel:route>
> > >> >> >            <camel:from uri="direct:genEvent"/>
> > >> >> >            <camel:wireTap uri="direct:wireTap"/>
> > >> >> >            <camel:transacted ref="mandatory"/>
> > >> >> >            <camel:to uri="activemq:topic:event-notifications"/>
> > >> >> >        </camel:route>
> > >> >> >
> > >> >> >        <camel:route>
> > >> >> >            <camel:from uri="direct:wireTap"/>
> > >> >> >            <camel:to uri="log:logger?showAll=true"/>
> > >> >> >        </camel:route>
> > >> >> >    </camel:camelContext>
> > >> >> >
> > >> >> > Code:
> > >> >> >
> > >> >> >        ProducerTemplate pt = camelCtx.createProducerTemplate();
> > >> >> >
> > >> >> >        Map<String, Object> headers = new HashMap<String,
> Object>();
> > >> >> >        headers.put("EventType", eventType);
> > >> >> >        headers.put("ClientID", 0);
> > >> >> >        headers.put("EntityType", "Address");
> > >> >> >
> > >> >> >        pt.sendBodyAndHeaders("direct:genEvent",
> > getAddress(addressID),
> > >> >> > headers);
> > >> >> >
> > >> >> >
> > >> >> > Like I mentioned, the code all works in the success case
but
> > doesn't
> > >> >> > rollback the JMS message in the failure case. Apparently
the
> > >> transaction
> > >> >> > context isn't being passed on to the camel route even though
it's
> > >> using
> > >> >> the
> > >> >> > same transaction manager under the covers. Is that by design
or
> is
> > >> there
> > >> >> a
> > >> >> > way to make this scenario work? We'd really like to be able
use
> the
> > >> camel
> > >> >> > route approach so we can do more complex things than what
I show
> > here.
> > >> >> >
> > >> >> > Thanks,
> > >> >> > Chris
> > >> >> >
> > >> >>
> > >>
> > >>
> > >>
> > >> --
> > >> Claus Ibsen
> > >> -----------------
> > >> CamelOne 2012 Conference, May 15-16, 2012: http://camelone.com
> > >> FuseSource
> > >> Email: cibsen@fusesource.com
> > >> Web: http://fusesource.com
> > >> Twitter: davsclaus, fusenews
> > >> Blog: http://davsclaus.blogspot.com/
> > >> Author of Camel in Action: http://www.manning.com/ibsen/
> > >>
> >
> >
> >
> > --
> > Claus Ibsen
> > -----------------
> > CamelOne 2012 Conference, May 15-16, 2012: http://camelone.com
> > FuseSource
> > Email: cibsen@fusesource.com
> > Web: http://fusesource.com
> > Twitter: davsclaus, fusenews
> > Blog: http://davsclaus.blogspot.com/
> > Author of Camel in Action: http://www.manning.com/ibsen/
> >
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message