camel-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Chris Geer <ch...@cxtsoftware.com>
Subject Re: OSGI Transaction Propagation to Camel Route
Date Tue, 17 Apr 2012 15:53:12 GMT
Raul,

I gave that a shot but it actually made the problem worse.
ProducerTemplate.requestBodyAndHeader uses an InOut exchange pattern but
since I'm not sending responses it always fails (regardless of transaction)
with a timeout saying it didn't get a response. It also send the message to
the topic even without the transaction being committed so it wouldn't solve
the transaction problem anyway.

Chris

On Tue, Apr 17, 2012 at 1:47 AM, Raul Kripalani <raul@fusesource.com> wrote:

> 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