Spring 4: ThreadPoolTaskExecutor transaction management issue - spring-transactions

We recently upgraded our spring version to 4.x from 2.x which started causing some issues with one of our 'threadpooltaskexecutor' implementation.
The implementation was as below:
public class A
{
..............................
..............................
public void create()
{
this.threadPoolTaskExecutor.execute(new Runnable()
{
public void run()
{
createABCAsync();
}
});
}
public void createABCAsync()
{
createABC();
}
public void createABC()
{
.....................................
.....................................
abcDAO.saveOrUpdate(abc);
xyzDAO.saveOrUpdate(xyz);
}
...................................................
...................................................
}
The bean definitions for class A has entries like below:
`<bean id="clsIntegrationManager" parent="txProxyTemplate"`>
.................................................
.................................................
<property name="transactionAttributes">
<props>
<prop key="create">PROPAGATION_REQUIRED</prop>
<prop key="createABCAsync">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
After spring upgrade, the above code threw an exception as below:
Exception in thread "threadPoolTaskExecutor-1" org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
To resolve the above I added an entry like follows in the DAO layer bean definition file:
<bean id ="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="checkWriteOperations" value="false"/>
</bean>
The above entry resolved the exception, but the asynchronous method execution which starts a separate transaction using REQUIRES_NEW is not doing any database commits. We have a couple of 'saveOrUpdate()' calls inside the createABC() method but nothing gets saved in database.
Can someone please help in understanding what is going wrong above ?
I tried a few different solution approaches, one of which is described here: [Spring TaskExecutor Transaction Lost (Proxy vs. Direct call) but this did not help.

Related

How to create a date range as a condition of a promotion in hybris?

is it possible to create a date condition for promotion in hybris?
I am trying to do this implementation. my first problem is how to map the parameter value
<bean id="dateRuleParameterValueMapperDefinition" class="de.hybris.platform.ruleengineservices.rule.strategies.impl.RuleParameterValueMapperDefinition">
<property name="mapper" ref="dateRuleParameterValueMapper" />
<property name="type" value="java.util.Date" />
</bean>
in this mapping, I have an exception that the type is not supported (Caused by: de.hybris.platform.ruleengineservices.rule.strategies.RuleParameterValueMapperException:)
if so, can I resolve this error .. is it possible to create a date condition in the RuleConditionTranslator?
hybris version: 6.5
If you want to add any new RuleParameterValueMapperDefinition, you have to implement 'RuleParameterValueMapper' and override 'toString' and 'fromString' methods in your mapper implementation.
public class MediaTypeRuleParameterValueMapper implements RuleParameterValueMapper<MediaModel>
{
#Resource
MediaService mediaService;
#Override
public String toString(final MediaModel mediaModel)
{
Preconditions.checkArgument(Objects.nonNull(mediaModel), "mediaModel must not be null!");
return mediaModel.getCode();
}
#Override
public MediaModel fromString(final String mediaCode)
{
try
{
return mediaService.getMedia(mediaCode);
}
catch (UnknownIdentifierException e)
{
e.message()
}
return null;
}
}
Now create a custom mapper definition (RuleParameterValueMapperDefinition)
<bean id="mediaTypeRuleParameterValueMapper" class="com.hybris.MediaTypeRuleParameterValueMapper"/>
<bean id="mediaTypeRuleParameterValueMapperDefinition" class="de.hybris.platform.ruleengineservices.rule.strategies.impl.RuleParameterValueMapperDefinition">
<property name="mapper" ref="mediaTypeRuleParameterValueMapper"/>
<property name="type" value="ItemType(Media)"/>
</bean>
Now you are ready to use
RuleConditionDefinitionParameter.type=ItemType(Media)
I don't believe that you need to map a date in that way, it should be treated the same as a String or Integer. So for reference look at the way any of the String or Integer parameters are handled.
My basis for saying this is the following from ruleengineservices-spring-rule.xml:
<alias name="defaultRuleParameterSupportedTypes" alias="ruleParameterSupportedTypes" />
<util:set id="defaultRuleParameterSupportedTypes" value-type="java.lang.String">
<value>java.lang.Boolean</value>
<value>java.lang.Character</value>
<value>java.lang.String</value>
<value>java.lang.Byte</value>
<value>java.lang.Short</value>
<value>java.lang.Integer</value>
<value>java.lang.Long</value>
<value>java.lang.Float</value>
<value>java.lang.Double</value>
<value>java.math.BigInteger</value>
<value>java.math.BigDecimal</value>
<value>java.util.Date</value>
<value>java.lang.Enum</value>
<value>java.util.List</value>
<value>java.util.Map</value>
</util:set>

MQ Listener Performance

I am building Docker Containers which have a war file running on Jetty, and I have been alternating a few settings to see if performance improves but nothing so far. Per container it has been achieving 7 tps.
The settings are
<bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="MQConnectionFactory" />
<property name="sessionCacheSize" value="10"/>
</bean>
<bean id="requestQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg index="0" value="${queuemanager}"/>
<constructor-arg index="1" value="${incoming.queue}"/>
</bean>
<integration:poller id="poller" default="true" fixed-delay="1000" error-channel="errorChannel"/>
How can I improve the number of threads processing over here?
Also, my connection factory details are as shown below
#Bean(name="DefaultJmsListenerContainerFactory")
public DefaultJmsListenerContainerFactory provideJmsListenerContainerFactory(PlatformTransactionManager transactionManager) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setTransactionManager(transactionManager);
factory.setConcurrency(jmsConcurrency);
factory.setCacheLevel(jmsCacheLevel);
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
factory.setSessionTransacted(true);
return factory;
}
#Bean(name = "txManager")
public PlatformTransactionManager provideTransactionManager() {
return new JmsTransactionManager(connectionFactory());
}
#Bean(name = "JmsTemplate")
public JmsTemplate provideJmsTemplate() {
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory());
jmsTemplate.setReceiveTimeout(Long.parseLong(env.getRequiredProperty(RECEIVE_TIMEOUT)));
return jmsTemplate;
}
#Bean(name="MQConnectionFactory")
public ConnectionFactory connectionFactory() {
if (factory == null) {
factory = new MQXAConnectionFactory();
try {
factory.setHostName(env.getRequiredProperty(HOST));
factory.setPort(Integer.parseInt(env.getRequiredProperty(PORT)));
factory.setQueueManager(env.getRequiredProperty(QUEUE_MANAGER));
factory.setChannel(env.getRequiredProperty(CHANNEL));
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
return factory;
}
The initial setting for the concurrency was '1-2' and I changed that to '10-15'. Did not affect performance.
The jmsCache was set to 3 (Consumer cache), but no change there yet either.
Any help is much appreciated.
Cheers
Kris
Answering my own post here. What we found out was that the problem was actually with our Database pooling not setup correctly in the first place.
But in order to increase the Listener count, I had to change my Spring integration adapter settings
<jms:message-driven-channel-adapter id="jmsIn"
destination="requestQueue"
channel="inputJsonConversionChannel"
connection-factory="cachingConnectionFactory"
error-channel="errorChannel"
concurrent-consumers="${jms_adapter_concurrent_consumers}" />
Only when the concurrent-consumers is varied, does the number of listeners on the queue increase.

Gridgain Error Suppressed: class org.gridgain.grid.GridException: Failed to serialize object

I am trying to put a key as String , value as List Intervals> in the cache and I am getting the below error. I have a put method in dao as generalised as object,object> so it can be used for difference cache
Input
[MAC4, [com.xx.Interval#1bccacc7]]
[MAC3, [com.xx.Interval#754b3232]]
[MAC1, [com.xx.Interval#78cf9e78, com.xx.Interval#6ad163f]]
MAC* is the key and List of Interval Objects are values.
Code:
griddao.put("intervals",tuple.getValue(0),tuple.getValue(1));
In griddao
public void put(String cacheName, Object key, Object value) throws GridException {
GridCache<Object, Object> cache = caches.get(cacheName);
if ( cache != null ) {
cache.put(key, value);
}
else {
LOG.error( "Cache is null");
}
It looks like you forgot to attach the actual error you got. Please provide full exception trace.
For now you can check whether Interval class implements Serializable. If it doesn't and you can't change it, configure marshaller not to require Serializable interface, like this:
<bean id="grid.cfg" class="org.gridgain.grid.GridConfiguration">
...
<property name="marshaller">
<bean class="org.gridgain.grid.marshaller.optimized.GridOptimizedMarshaller">
<property name="requireSerializable" value="false"/>
</bean>
</property>
...
</bean>

Spring equivalent of CompletionService?

In my app I have to process multiple jobs asynchronously from the main application thread and collect the result of each job. I have a plain Java solution that does this using a ExecutorService and a ExecutorCompletionService that collects the job results.
Now I would like to convert my code to a Spring solution. The docs show me how the use the ExecutorService and the #Async annotation, but I am not sure how and if I can collect the results of multiple jobs.
In other words: I am looking for the Spring equivalent of the CompletionService. Is there such a thing?
My current code:
class MyService {
private static ExecutorService executorService;
private static CompletionService<String> taskCompletionService;
// static init block
static {
executorService = Executors.newFixedThreadPool(4);
taskCompletionService = new ExecutorCompletionService<String>(executorService);
// Create thread that keeps looking for results
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Future<String> future = taskCompletionService.take();
String s = future.get();
LOG.debug(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}).start();
}
// This method can and will be called multiple times,
// so multiple jobs are submitted to the completion service
public void solve(List<Long> ids) throws IOException, SolverException {
String data = createSolverData(ids);
taskCompletionService.submit(new SolverRunner(data, properties));
}
}
You need to consider what's your main goal, because your current code will work fine alongside other Spring-associated classes. Spring provides support for native Java ExecutorService as well as other popular 3rd party library such as Quartz
Probably what you're after is setting up the executor service on the spring container (eg: using following config on your spring beans xml)
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
And decorate your MyService class with #Service annotation and inject the reference to the executor service
I ended up defining my beans in the Spring application context and injection the completionservice into MyService. Works as a charm.
<task:executor id="solverExecutorService" pool-size="5" queue-capacity="100" />
<spring:bean id="solverCompletionService" class="nl.marktmonitor.solver.service.SolverCompletionService" scope="singleton">
<constructor-arg name="executor" ref="solverExecutorService"/>
</spring:bean>

LazyInitializationException in Thread with Spring Roo 1.5

I have a project with Spring Roo 1.5 (mysql w/ hibernate), I made a Thread class (extends from Thread) because I need call to async operations. But when I tried to get this, for example a property from persitence class occurs a exception. This only occurs when I call from Thread class...
My entity class:
#RooJavaBean
#RooToString
#RooEntity
public class Consulta {
private String nombre;
#OneToMany(cascade=CascadeType.ALL)
private List<DetalleConsulta> detalleConsulta;
}
My thread:
public class ThreadIngresarConsulta extends Thread {
private Long idConsulta;
public ThreadIngresarConsultaCRM(Long idConsulta) {
super("ThreadIngresarConsultaCRM");
this.idConsulta = idConsulta;
}
public void run(){
try {
Consulta consulta = Consulta.findConsulta(idConsulta);
List<DetalleConsulta> lista = consulta.getDetalleConsulta();
}catch(Exception e) {
System.err.println(e.getMessage());
}
}
}
ApplicactionContext (generated by roo)
...
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
And this is the exception:
011-12-05 18:49:10,015 [ThreadIngresarConsulta] ERROR org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: com.core.Consulta.detalleConsulta, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.core.Consulta.detalleConsulta, no session or session was closed
Has anyone tried to call an entity JPA within a thread?
Try putting an #Transactional annotation on the run method of your thread. If that doesn't work move the two lines into a separate method and add #Transactional on that method.
public class ThreadIngresarConsulta extends Thread {
public void run(){
doProcess();
}
#Transactional
public void doProcess() {
try {
Consulta consulta = Consulta.findConsulta(idConsulta);
List<DetalleConsulta> lista = consulta.getDetalleConsulta();
}catch(Exception e) {
System.err.println(e.getMessage());
}
}
}

Resources