spring jms - perform action before message received - spring

Is it possible to perform an action before a jms message is received in spring boot? I know I could put it at the very top of my #JmsListener, but I have several listeners and I'd prefer avoiding adding a call to all of them.
I'm trying to use the logging MDC (a threadlocal, if you're not familiar with the MDC,) to track various things and I'd like to set some properties before beginning to process the message. I can do this on my controllers with a Filter, but does spring jms have the same concept?

I would try to start with an Before or Around (in case there should be some logic implemented after handling message as well) aspect:
#Before("#annotation(JmsListener)")
public void handle(ProceedingJoinPoint joinPoint) { ... }
#Around("#annotation(JmsListener)")
public void handle(ProceedingJoinPoint joinPoint) { ... }
Couple of links: enabling aspectj support, before advice, around advice.

Related

Count AsyncResponse calls in spring boot metrics

I have a JAX-RS service backend written in Spring boot 2 and using micrometer for metrics.
By default the metrics contain very nice http metrics as http_server_requests_seconds_count.
These work great for normal GET and PUT requests. One method in my service uses JAX-RS AsyncRequest though.
#GET
#Produces(APPLICATION_JSON)
#Path("next/{position}")
public void getNext(
#PathParam("position") Long position,
#Suspended final AsyncResponse response) throws InterruptedException {
...
// Somewhere in the code in another thread I invoke
response.resume(entity);
...
}
These calls do not seem to be counted at all. Is there a way to enable counting them?
If not should I simply feed the same counters manually from my code?

JmsListener called again and again when a error happen in the method

In a spring boot application, I have a class with jms listener.
public class PaymentNotification{
#JmsListener(destination="payment")
public void receive(String payload) throws Exception{
//mapstring conversion
....
paymentEvent = billingService.insert(paymentEvent); //transactional method
//call rest...
billingService.save(paymentEvent);
//send info to jms
}
}
I saw then when a error happen, data is inserted in the database, that ok, but it's like receive method is called again and again... but queue is empty when I check on the server.
If there is an error, I don't want method is called again, Is there something for that.
The JMS Message Headers might contain additional information to help with your processing. In particular JMSRedelivered could be of some value. The Oracle doc states that "If a client receives a message with the JMSRedelivered field set, it is likely, but not guaranteed, that this message was delivered earlier but that its receipt was not acknowledged at that time."
I ran the following code to explore what was available in my configuration (Spring Boot with IBM MQ).
#JmsListener(destination="DEV.QUEUE.1")
public void receive(Message message) throws Exception{
for (Enumeration<String> e = message.getPropertyNames(); e.hasMoreElements();)
System.out.println(e.nextElement());
}
From here I could find JMSXDeliveryCount is available in JMS 2.0. If that property is not available, then you may well find something similar for your own configuration.
One strategy would be to use JMSXDeliveryCount, a vendor specific property or maybe JMSRedelivered (if suitable for your needs) as a way to check before you process the message. Typically, the message would be sent to a specific blackout queue where the redelivery count exceeds a set threshold.
Depending on the messaging provider you are using it might also be possible to configure back out queue processing as properties of the queue.

How to transact in batches in camel

I am doing some ETL that process some input CSV files and load then to Neo4j using Spring data Neo4j.
I have 2 routes one that takes the input CSV split by line and send to the second route that does the load line by line in transnational mode.
The following is the first route
#Override
void configure() throws Exception {
from(endpoint)
.id('CSV_ROUTE')
.unmarshal(buildCsvDataFormat())
.split(body())
.streaming()
.parallelProcessing()
.recipientList(header('IMPORTER_ROUTE'))
And the following is the second route
#Override
void configure() throws Exception {
from(endpoint)
.transacted()
.id(routeId)
.bean(importer)
}
How can I make transaction to commit in batches for example of 10 lines instead of every line ?
Thank you
Luis Oscar
You cannot do this. Transactions is per message in Camel.
Also mind transaction is not some magic fairy dust you can turn on and then anything you touch becomes transactional.
In Java transactions often only work with transactional resources such as JDBC and JMS.

Spring Hibernate eats exceptions

With #Transaction and with trace level logging of Spring I see that Hibernate has an exception on a db constraint but it just rolls back the transaction. I tried using #Exception without success to try to catch it.
I see a suggestion online to use Spring AOP #AfterThrowing to catch such events.
This seems like a rather complex way to handle a commonplace event. It seems so much easier with try/catch and old fashioned commits/rollbacks. Is there no better way
in Spring Hibernate?
I'm processing XML messages from a queue. Depending on the type of the exception I get I might want to just catch it and put the bad incoming queue message into an db error table and continue the transaction. (If I just blindly rollback the message will get put back on the queue which might be good in some cases but not in others).
From what I've read there are ways of being made aware of some errors (for some reason not the constraint error) and logging them. Are there ways of interrupting the transaction after an exception and deciding if one wants to commit, continue or rollback?
If not, can one use old style commits and rollback with spring hibernate?
Configure SimpleMappingException resolver and log the exception there:
public class MyExceptionResolver extends SimpleMappingExceptionResolver {
private Logger logger = LoggerFactory.getLogger(MyExceptionResolver .class);
#Override
protected void logException(Exception ex, HttpServletRequest request) {
this.logger.warn(buildLogMessage(ex, request), ex);
}
<bean class="com.mypackage.MyExceptionResolver"/>
EDIT:
You can choose to do anything. The above class has nothing to do with rolling back. It's useful to intercept exceptions and do whatever you want with them.
By default, Spring rolls back for any RuntimeException.
If you want to configure rollback policy:
#Transactional(rollbackFor = { CustomException.class})
or
#Transactional(noRollBackFor= { CustomException.class})

Does Spring's PlatformTransactionManager require transactions to be committed in a specific order?

I am looking to retrofit our existing transaction API to use Spring’s PlatformTransactionManager, such that Spring will manage our transactions. I chained my DataSources as follows:
DataSourceTransactionManager - > LazyConnectionDataSourceProxy - > dbcp.PoolingDataSource - > OracleDataSource
In experimenting with the DataSourceTransactionManager , I have found that where PROPAGATION_REQUIRES_NEW is used, it seems that Spring’s transaction management requires that the transactions be committed/rolled back in LIFO fashion, i.e. you must commit/rollback the most recently created transactions first.
Example:
#Test
public void testSpringTxns() {
// start a new txn
TransactionStatus txnAStatus = dataSourceTxnManager.getTransaction(propagationRequiresNewDefinition); // specifies PROPAGATION_REQUIRES_NEW
Connection connectionA = DataSourceUtils.getConnection(dataSourceTxnManager.getDataSource());
// start another new txn
TransactionStatus txnBStatus = dataSourceTxnManager.getTransaction(propagationRequiresNewDefinition);
Connection connectionB = DataSourceUtils.getConnection(dataSourceTxnManager.getDataSource());
assertNotSame(connectionA, connectionB);
try {
//... do stuff using connectionA
//... do other stuff using connectionB
} finally {
dataSourceTxnManager.commit(txnAStatus);
dataSourceTxnManager.commit(txnBStatus); // results in java.lang.IllegalStateException: Cannot deactivate transaction synchronization - not active
}
}
Sadly, this doesn’t fit at all well with our current transaction API which allows you to create transactions, represented by Java objects, and commit them in any order.
My question:
Am I right in thinking that this LIFO behaviour is fundamental to Spring’s transaction management (even for completely separate transactions)? Or is there a way to tweak its behaviour such that the above test will pass?
I know the proper way would be to use annotations, AOP, etc. but at present our code is not Spring-managed, so it is not really an option for us.
Thanks!
yes,I have met the same problems below when using spring:
java.lang.IllegalStateException: Cannot deactivate transaction synchronization - not active.
According above,Spring’s transaction management requires that the transactions be committed/rolled back in LIFO fashion(stack behavior).The problem disappear.
thanks.
Yes, I found this same behavior in my own application. Only one transaction is "active" at a time, and when you commit/rollback the current transaction, the next active transaction is the next most recently started transaction (LIFO/stack behavior). I wasn't able to find any way to control this, it seems to be built into the Spring Framework.

Resources