Conflicting Spring schedules - java

I've two scheduled tasks that run at different time intervals. The first task is scheduled to run every 5 seconds and the second task is scheduled to run every 10 minutes.
#EnableScheduling
public class ScheduledTask {
#Autowired
private taskService taskService;
#Scheduled(every 5 second)
public void scheduleTaskA() {
taskService.taskA()
}
#Scheduled(every 10 minute)
public void scheduleTaskB() {
taskService.taskB()
}
}
public class TaskServiceImpl implements TaskService {
#PersistenceContext
private EntityManager entityManager;
void taskA(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure1");
if(query.execute())
query.getSingleResult();
}
void taskB(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure2");
if(query.execute())
query.getSingleResult();
}
}
Every time the second task is running it throws java.lang.IllegalStateException: Session/EntityManager is closed. Looks like the first task is closing the entityManager. How can I avoid this without changing #PersistenceContext annotation?
Full stack trace
java.lang.IllegalStateException: Session/EntityManager is closed
at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:357) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:138) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.query.internal.AbstractProducedQuery.getMaxResults(AbstractProducedQuery.java:892) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.procedure.internal.ProcedureCallImpl.getResultList(ProcedureCallImpl.java:716) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.procedure.internal.ProcedureCallImpl.getSingleResult(ProcedureCallImpl.java:744) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at sun.reflect.GeneratedMethodAccessor150.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:374) ~[spring-orm-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at com.sun.proxy.$Proxy149.getSingleResult(Unknown Source) ~[na:na]
at com.test.service.TaskServiceImpl.taskA(TaskServiceImpl.java:602) ~[classes/:0.0.1-SNAPSHOT]
at com.test.service.TaskServiceImpl....(TaskServiceImpl.java:112) ~[classes/:0.0.1-SNAPSHOT]
at com.test.service.TaskServiceImpl....(TaskServiceImpl.java:163) ~[classes/:0.0.1-SNAPSHOT]
at com.test.schedule.ScheduledTask.scheduledTaskA(ScheduledTask.java:45) ~[classes/:0.0.1-SNAPSHOT]
at sun.reflect.GeneratedMethodAccessor143.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_171]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]

I'm pretty sure you need to run the StoredProcedureQuery(s) in a transactional context. Please try adding #Transactional to each of your methods.
#Transactional
void taskA(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure1");
if(query.execute())
query.getSingleResult();
}
#Transactional
void taskB(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure2");
if(query.execute())
query.getSingleResult();
}
You might also want to set the propagation to new to insure these each run within their own separate transaction #Tansacational(propagation = Propagation.REQUIRES_NEW) .

You are getting the error because you are trying to share same entity manager. Which is short living object.
You can apply following two solutions :
1) Inject EntityManagerFactory and inside of EntityManager, in method use factory to create EntityManager.
#PersistenceUnit(unitName= "em")
private EntityManagerFactory emf;
2) Create two different services let each service have there own entity manger instance.
(Not sure it will work second time when method will called by scheduler. Test it and let me know.)

Related

Spring Boot scheduled Runnable tasks continue executing even after server is shut down with an actuator

I'm currently developing a Spring-based web platform which makes use of several scheduled processes that access a central database. I wanted to introduce actuators for shutdown and restart. However, I am experiencing an issue: even though the shutdown request is accepted with a 200 response, the application context begins shutting down:
2022-10-10 17:37:25.235 INFO 9067 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2022-10-10 17:37:25.240 INFO 9067 --- [ Thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
And after that, I repeatedly get the following exception:
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: EntityManagerFactory is closed
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:467) ~[spring-orm-5.3.16.jar:5.3.16]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400) ~[spring-tx-5.3.16.jar:5.3.16]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) ~[spring-tx-5.3.16.jar:5.3.16]
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:595) ~[spring-tx-5.3.16.jar:5.3.16]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:382) ~[spring-tx-5.3.16.jar:5.3.16]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.16.jar:5.3.16]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.16.jar:5.3.16]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.16.jar:5.3.16]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.16.jar:5.3.16]
at usi.si.seart.service.TaskService$TaskServiceImpl$$EnhancerBySpringCGLIB$$4bf83a1d.getNext(<generated>) ~[classes/:na]
at usi.si.seart.scheduling.TaskRunner.run(TaskRunner.java:68) ~[classes/:na]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.3.16.jar:5.3.16]
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[na:na]
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: java.lang.IllegalStateException: EntityManagerFactory is closed
at org.hibernate.internal.SessionFactoryImpl.validateNotClosed(SessionFactoryImpl.java:547) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.hibernate.internal.SessionFactoryImpl.createEntityManager(SessionFactoryImpl.java:636) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.hibernate.internal.SessionFactoryImpl.createEntityManager(SessionFactoryImpl.java:158) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.createNativeEntityManager(AbstractEntityManagerFactoryBean.java:585) ~[spring-orm-5.3.16.jar:5.3.16]
at jdk.internal.reflect.GeneratedMethodAccessor112.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:487) ~[spring-orm-5.3.16.jar:5.3.16]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:734) ~[spring-orm-5.3.16.jar:5.3.16]
at com.sun.proxy.$Proxy175.createNativeEntityManager(Unknown Source) ~[na:na]
at org.springframework.orm.jpa.JpaTransactionManager.createEntityManagerForTransaction(JpaTransactionManager.java:485) ~[spring-orm-5.3.16.jar:5.3.16]
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:410) ~[spring-orm-5.3.16.jar:5.3.16]
... 17 common frames omitted
So in spite of the fact that the server is reported as "shutting down", the scheduled processes still continue executing. My scheduler definition within the configuration class is as follows:
#Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setClock(Clock.systemUTC());
threadPoolTaskScheduler.setPoolSize(3);
threadPoolTaskScheduler.setThreadNamePrefix("PlatformScheduler");
threadPoolTaskScheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
threadPoolTaskScheduler.initialize();
threadPoolTaskScheduler.schedule(getRepoMaintainer(), new CronTrigger("0 0 0 * * SUN"));
threadPoolTaskScheduler.schedule(getTaskCleaner(), new CronTrigger("0 */15 * * * *"));
threadPoolTaskScheduler.scheduleWithFixedDelay(getTaskRunner(), 500);
return threadPoolTaskScheduler;
}
Where the getRepoMaintainer, getTaskCleaner and getTaskRunner are all methods that produce custom Runnable instances: RepoMaintainer, TaskCleaner and TaskRunner respectively.
Unfortunately, none of the fixes suggested by the other users worked. In the end, I managed to solve my problem by virtue of a custom ThreadPoolTaskScheduler implementation:
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler() {
private final Set<ScheduledFuture<?>> futures = new HashSet<>();
#Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
ScheduledFuture<?> future = super.scheduleWithFixedDelay(task, delay);
futures.add(future);
return future;
}
#Override
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
ScheduledFuture<?> future = super.schedule(task, trigger);
futures.add(future);
return future;
}
#Override
public void shutdown() {
futures.forEach(future -> future.cancel(true));
super.shutdown();
}
};
This way I ensure that all scheduled tasks are cancelled pre-shutdown no matter what.
As you have specified that your custom destroyMethod is "shutdown" have you defined that method with the required destruction statements?
Something like this,
public void shutdown() {
threadPoolTaskScheduler.shutdown();
}
Edit-
Most probably the error here is, even though the shutdown has been initiated the tasks are still running but the container is shutting down. This releases the resources required for the task to execute and the error is thrown.
What you can do here is perform a graceful shutdown where you prevent the shutdown of the container until the tasks have finished executing.
Your issue is similar to this one and you can try out his solution.
Or, you can configure a termination period like so, setAwaitTerminationSeconds(*seconds*) Check more here. But then you might face this issue.

could not initialize proxy [###] - no Session

I have coded with java, hibernate and spring. This error comes up when trying to add the #Scheduled annotation. Without Annotate using #Scheduled it works fine. what is the reason caused for this error?
Error as follows,
xyzLib: could not initialize proxy [ABC#8] - no Session
at xyzService.customMethod(xyzService.java:1392) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_291]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_291]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_291]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_291]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.3.2.jar:5.3.2]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.3.2.jar:5.3.2]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_291]
at java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308) [na:1.8.0_291]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java) [na:1.8.0_291]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_291]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_291]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_291]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_291]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_291]
Hope someone can help me to understand what is happening.
Without knowing the details you may need to add something like this above the method
#Transactional(propagation = Propagation.REQUIRES_NEW)
This error means that we try to fetch a lazy-loaded object from the database by using a proxy object, but the Hibernate session is already closed.
I have fixed this error using FetchType.EAGER strategy.
I use this strategy along with a #OneToMany annotation, for example :
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private Set<Role> roles;
This is a sort of compromised answer for a precise utilization when we want to fetch the related series for most of our use cases.
So it is a lot simpler to declare the EAGER fetch kind as an alternative to explicitly fetching the series for most of the special enterprise flows.
more about this please refer to this link.

Why is Environment variable always null when reading from properties file?

I am new to using application.properties and am struggling because Environment is always null. I have followed numerous examples such as the accepted answer shown on SO HERE; however, I keep getting the error message showing below. This is a Spring application and I know I don't actually need to go through this manual process per the article HERE. However, I have to show how to connect manually using the properties file. Where am I going wrong? Effectively, I want to hide my database credentials in application.properties and then read them into something like DriverManager.getConnection(env.getProperty("URL"), env.getProperty("USERNAME", env.getProperty("PASSWORD");
Attempting to use Environment:
#Component
#PropertySource("classpath:application.properties")
public class OpenConnection {
private volatile Connection con;
#Autowired
private Environment env;
public OpenConnection() {
}
#Bean
public Connection getInstance() {
try {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
con = dataSource.getConnection();
} catch (SQLException e) {
handleException(e);
}
return con;
}
application.properties
# MySQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/rentalportfolio?useTimezone=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
Error message
java.lang.NullPointerException: null
at com.crd.carrental.database.connectionoperations.OpenConnection.getInstance(OpenConnection.java:43) ~[classes/:na]
at com.crd.carrental.database.selectoperations.SelectExistingReservation.<init>(SelectExistingReservation.java:24) ~[classes/:na]
at com.crd.carrental.controllers.ExistingReservationController.lookupReservationId(ExistingReservationController.java:24) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_261]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_261]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_261]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_261]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171) ~[spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120) ~[spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:565) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:511) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:94) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:520) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:454) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:144) [spring-messaging-5.3.3.jar:5.3.3]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_261]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_261]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_261]
I think that the problem is that you are using #Component on your OpenConnection rather than #Configuration
Here you can find some more examples, how to use properties in your Spring application
I recommend removing this OpenConnection class and let SpringBoot create your datasource for you on start up.
If you really want to create it yourself, check the docs. Here is an example:
#Configuration
public class DataSourceConfiguration {
#Bean
#ConfigurationProperties("spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}

#Transactional works on public method in service but not with protected method

I am trying to call a service method(B) from another service method(A) from same service impl class. Now when I put #Transactional on #A, everything works fine, but when I put the same on #B everything breaks apart. And the error that I get is
Exception: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: MyEntity.childs, could not initialize proxy - no Session
at <reference to my code>
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:685) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at <reference to my code>
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_162]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_162]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_162]
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:223) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:483) ~[spring-cloud-context-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at <reference to my code>
at <reference to my code>
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590) ~[na:1.8.0_162]
at <reference to my code>
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_162]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_162]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_162]
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: MyEntity.childs, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:582) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:201) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:561) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:132) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:277) ~[hibernate-core-5.2.16.Final.jar:5.2.16.Final]
at <reference to my code>
... 24 common frames omitted
My class call structure is like this
A = fail case
B = success case
doProcessS() ==> public void
doSubProcessS() ==> protected void
I am using SpringBoot 2.0.0.RELEASE
I want to execute everything in 'A' way and not 'B' as I want to execute another check in doProcessS() based on data committed to DB in doSubProcess()
#Transactional is based on Spring AOP
Spring AOP does not work in self-invocation method (Within the same class)
You can fix it by mark your doProcessS() in ServiceImpl as #Transactional
Reference
This means that method calls on that object reference will be calls on
the proxy, and as such the proxy will be able to delegate to all of
the interceptors (advice) that are relevant to that particular method
call. However, once the call has finally reached the target object,
the SimplePojo reference in this case, any method calls that it may
make on itself, such as this.bar() or this.foo(), are going to be
invoked against the this reference, and not the proxy. This has
important implications. It means that self-invocation is not going to
result in the advice associated with a method invocation getting a
chance to execute.
If you want to separate your transaction, delegate doSubProcessS to other class and mark it propagation type as Propagation.REQUIRES_NEW

Scope 'request' is not active for the current thread - websocket edition

I'm trying to create a websocket app using sprint boot and spring messaging. However, when i try to call a function inside one of our service classes, i got the following exception:
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at com.propspace.intl.psauth.service.PsSessionHandler.getCurrentRequest(PsSessionHandler.java:83) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.psauth.service.PsTokenService.getTokenValue(PsTokenService.java:167) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.psauth.service.PsTokenService.getCurrentToken(PsTokenService.java:66) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.psauth.service.AuthPersistenceService.getCurrentUser(AuthPersistenceService.java:124) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.psauth.service.AuthPersistenceService$$FastClassBySpringCGLIB$$b662e141.invoke(<generated>) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:121) ~[spring-retry-1.1.1.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at com.propspace.intl.psauth.service.AuthPersistenceService$$EnhancerBySpringCGLIB$$d5176572.getCurrentUser(<generated>) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.psauth.service.AuthorizationService.getCurrentLoggedInUser(AuthorizationService.java:115) ~[propspace-auth-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.common.service.PsNotificationHandler.refindUserId(PsNotificationHandler.java:196) ~[propspace-common-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.common.service.PsNotificationHandler.getAllNotificationsOfUser(PsNotificationHandler.java:68) ~[propspace-common-0.1.6-SNAPSHOT.jar:na]
at com.propspace.intl.pushnotifications.controller.NotificationController.greeting(NotificationController.java:47) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:198) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:116) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:490) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:497) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:87) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:451) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:389) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]
After doing some reading on it, it turned out i needed to make this service (bean) a scoped bean, so i did this:
#Scope(value= "request", proxyMode=org.springframework.context.annotation.ScopedProxyMode.TARGET_CLASS)
On my bean class, and in my controller i did this:
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
After doing those changes, the exception changes to the following:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.notificationController': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.getTarget(CglibAopProxy.java:685) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:636) ~[spring-aop-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at com.propspace.intl.pushnotifications.controller.NotificationController$$EnhancerBySpringCGLIB$$d92fa60c.greeting(<generated>) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:198) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:116) ~[spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:490) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:497) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:87) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:451) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:389) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) [spring-messaging-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:41) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
... 20 common frames omitted
Here's my config class:
#Configuration
#EnableWebSocketMessageBroker
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").withSockJS();
}
#Bean()
public NotificationHandler notificationHandler( ) {
return new PsNotificationHandler();
}
#Bean
#ConditionalOnMissingBean
public RequestContextFilter requestContextFilter() {
RequestContextFilter rcf = new RequestContextFilter();
rcf.setThreadContextInheritable(true);
return rcf;
}
#Bean
#ConditionalOnMissingBean
public RequestContextListener RequestContextListener() {
return new RequestContextListener();
}
#Bean
public HttpSessionIdHandshakeInterceptor httpSessionIdHandshakeInterceptor() {
return new HttpSessionIdHandshakeInterceptor();
}
}
My code is mostly based on a sample code for running websockets with spring boot, except for this part:
Object nots = notificationHandler.getAllNotificationsOfUser(null, false, false);
where i'm getting the notifications, help appreciated
Here's a stripped down version of the code
http://www.4shared.com/file/BinrToCqce/pushnotifications.html
Seems to be Message broker has its own thread. So Message broker and DispathcherServlet work in different threads. But you can't use HttpServletRequest from another thread. Because, when asynchronous job will try to process HttpServletRequest, there is possibility that request(or session) is not actual or does not exist anymore. This is means, that you can't use request scoped beans as well as session scoped beans outside of DispatcherServlet's thread.
Since, you can't access request or session data directly from another thread you have to pass this data manually.

Categories