I am facing an issue regarding @Async
task with HttpSession. I want to save the data in session in an async method. What happens is the response is returned correctly but I get an error while saving data in session. Please help.
My controller file:
@RequestScope
@Controller
public class SomeController {
@Autowired
private ISomeService iSomeService;
@ResponseBody
@GetMapping("/some-func")
public String someFunc() {
iSomeService.myAsyncFunction("hello");
return "ok";
}
}
My Service file:
@RequestScope
@Service
public class SomeServiceImpl implements ISomeService {
@Autowired
private HttpSession session;
@Async("threadPoolTaskExecutor")
@Override
public void myAsyncFunction(String s) {
session.setAttribute("key", s);
}
}
My configuration file:
@EnableAsync
@Configuration
public class ThreadConfig {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
My Stacktrace:
2019-03-07 17:23:16.065 ERROR 29179 --- [lTaskExecutor-1] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected error occurred invoking async method: public void com.example.demo.SomeServiceImpl.myAsyncFunction(java.lang.String)
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.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:309) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils.access$400(WebApplicationContextUtils.java:64) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:366) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:361) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:307) ~[spring-beans-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at com.sun.proxy.$Proxy93.setAttribute(Unknown Source) ~[na:na]
at com.example.demo.SomeServiceImpl.myAsyncFunction(SomeServiceImpl.java:21) ~[classes/:na]
at com.example.demo.SomeServiceImpl$$FastClassBySpringCGLIB$$9dbf1607.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_191]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_191]
On top of my head, If We have
@Async
annotations then I think return type should be of typeCompletableFuture
like a promise in javascript.So by changing the return type to service method from
void
toCompletableFuture<Void>
solves the problem.So I modified the code as below:
// To get session object in Async // This is bad code but check suitability
So here I am getting session object from the HttpRequest and passing it to Service, You add parameters at service and check those parameters at the controller.
Do not autowire session object at service or controller.
According to
Async
java doc.void
is a legal return type.I think this link may help you.