How to deal with thread in background processing java spring boot? - java

I want to download file after query but the time is too long, so my company said I should let the process in background.
For that I create thread when user call method, it will generate file and send to email of customer.
But the problem is about my thread, I also test function for sendemaildownload (it also includes the function which I use to query), I'm quite sure this problem from the way I create the thread.
This is what it says to me when I'm logging the error on creating the thread:
Exception in thread "Nathan-Transportation1" 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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Is there any way to fix it? I want to understand why it happend when I create my thread pool.

Try using #Async annotation.
For more information see here

This error message indicates that you are attempting to access request-scoped data (for example, request attributes) outside of the context of an HTTP request.
You can try the following solutions to this problem:
To expose the current request and make it accessible to your code,
use a RequestContextListener or RequestContextFilter.
To execute tasks in a background thread, use Spring's TaskExecutor interface, which will handle the necessary context management for you.
Here are some links that may be of interest to you:
RequestContextListener
RequestContextFilter
TaskExecutor

Related

Guice Request Scope for tracing workflow of request

I have a use case where I have 6 steps being performed in one request. The business is requesting that we capture metrics on what the result of each step was in the process. They want us to log to a Kinesis stream.
Architecturally I am looking at the best solution. We have java based services I want to have a request scoped object enriched as the request progresses, then when the endpoint finishes we would make a service call to kinesis asynchronous using a fire and forget pattern. This way the reporting is not holding up the main thread.
I was looking at using the raw ThreadLocal or guice scope. Has anyone ran into to a similar problem that they solved? Im thinking of use guice request scoped components, which will greatly simply the code. Just looking for some opinions. Thanks!
I'm assuming you aren't on a servlet environment because, then, you will just use the built in request scope. Even then you can use the request scope from guice-servlet building the scope yourself.
void processRequest() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
step1();
step2();
step3();
step4();
step5();
step6();
}
}
You can use #RequestScoped and it will be the same object on all your steps. You can, for example, use a provider to get access to it.

Java EE Request scope and Asynchronous

I am attempting to time an log performance using an interceptor.
#LogPerformance
#Interceptor
public class PerformanceInterceptor {
The times are stored in a request scoped bean. When the the request has finished the times are written to a log file.
When I changed several of the logged methods to be asynchronous, the logging for those operations stopped being output.
#Asynchronous
#LogPerformance
public Future<String> getString() {
I believe the new EJB thread is defining a new request scope. I can log output from the interceptor and see the request scoped object, but there are two different addresses attached to the objects. One address for the http thread and a different address for the EJB thread.
Is there a way to allow the interceptors from the async methods to write to the object in the http request scope? Is there another way to get the data back into the parent scope?
The container will propagate the javax.ejb.EJBContext to the thread that executes the asynchronous method.
You can inject this EJBContext into your interceptor and stash any state (such as your request scoped bean) that you want into it via javax.ejb.EJBContext.getContextData().

Using spring session scope without session

I have web application where I defined session scoped UserDetail. The problem is that I also have some Quartz jobs that should use UserDetail bean. When job is run I get:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.userDetails': Scope 'session' 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.
Inside job I need to inject some "technical user" details. Is it possible to properly handle situation when session is not present? Maybe any conditional injection?
EDIT 1
To clarify. I dont want to have session in my job service. This job modifies data and some audit log based on user data is saved to database. Normally user data comes from session but in job I need to provide some "static" technical user data. Any ideas?
Quartz does not know anything about "sessions", so if you want your background job to know the user that submitted the job, you have to pass that information to the job, likely in the DataMap of the trigger.

Call controller form another bean. No thread-bound request found

I'm developing a spring mvc and i want my controller to listen application events
via #controller I send a jms message from a web page
and I'm trying to notify the controller when receiving a message jms, in order to push some data to a web page
First I've tried with the observer pattern, implementing the controller as an ApplicationListener
# Controller ("MyController")
# Scope (value = "session" = proxyMode ScopedProxyMode.TARGET_CLASS)
public class MyController implements Serializable, ApplicationListener <CustomEvent>
Then I've tried to call a controller method from another bean when receiving a jms message
#Resource(name="MyController")
private MyController c;
c.update(String data);
But I'm getting always the same error
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.
Is there a way to call a controller from another bean?
Thanks
The problem is that your controller is session-scoped, and you try to call its method from a context where no HTTP session is available.
So, I assume that your controller combines functionality that depends on HTTP session (thus session scope), and functionality that need to be called outside of a session (such as your update() method).
If so, you can solve this problem by moving functionality that doesn't require HTTP session into separate bean (without session scope).

getRequestDispatcher() is returning null (Portlet)

I am working on a Java Portlet (extending GenericPortlet), using JBoss 7.02 and LifeRay Portal 6.1.0 GA1. This is one of the bundles that can be downloaded from LifeRay's release archive.
During deployment, when the init() method is called, getRequestDispatcher() returns null. Below is the exact error message:
09:22:15,972 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/my-portlet-name]] (MSC service thread 1-15) Error during mapping: java.lang.NullPointerException
Below is a snippet from my init() method:
PortletConfig config = getPortletConfig();
PortletContext context = getPortletContext();
PortletRequestDispatcher normalView = context.getRequestDispatcher("/portlet.jsp");
As a temporary workaround, I have moved all getRequestDispatcher() calls to doView() where it executes without problem. I do not understand why getRequestDispatcher() can locate portlet.jsp when called during doView, but not when its called during init()
Am I missing a preceding call of some other method that would resolve this? Is this a known issue?
Thanks for any help.
Getting the request dispatcher in the doView is the only place I've seen it done. I would imagine that it returns null during init because there is no actual request to dispatch.
Typically the init method is used for time-expensive operations that you don't want to incur for each request. This might be something like reading data from a file, or creating a reusable SQL connection.
You should also keep in mind that you should keep any portlet state thread safe. Don't create class or object variables that can only be used for one request at a time. The portlet methods are not inhererently thread safe, so you need to make sure that whatever variables a request is interacting with won't be manipulated by another request that is executing concurrently.
I'm not familiar with Portlets, but the answer should be the same as for Servlets.
The init() method is called exactly once, when your application is initially deployed. There is no active request (no one is asking for anything) or response (no one is going to read what the output is). Therefore, it is very reasonable forgetRequestDispatcher() to return null. In doView(), when you're handling a request and response, it makes sense to ask another resource to generate part (or all) of the response.
To address your question directly, getRequestDispatcher() has no problem locating portlet.jsp from init(); it's the request that's missing. (Where do you expect to see the result of portlet.jsp, anyway?)
If you do want to print some output during initialization, you can try logging it to a file, if your application is set up for that. Or, you can display data on System.out, if you know where the container's console is. (I use this second option quite often with servlets.)

Categories