share request context between threads - java

I have a Quarkus app with REST API and multiple services that are #ApplicationScoped, and one bean that is #RequestScoped (it has data related to JWT, cookies etc).
When the REST API is invoked, I want to do some work synchronously and then return an answer to the client but to keep doing async work with the same RequestScoped bean (context data).
I tried to propagate the RequestScoped bean to the thread that will handle the async task, but once the HTTP request is finished, the RequestScoped bean is getting deleted.
What is the correct way of doing this?
Basically I want to share some context across a flow that involves sync and async tasks

Related

Spring Boot Request-scoped bean is re-used for multiple requests

Our Spring Boot web application defines a bean that, upon construction, writes a unique ID to the SLF4J MDC (mapped diagnostic context) in order to make it clear in the logs which request caused which log message.
Therefore the bean is request-scoped, i.e. we expect it to only exist as long as exactly one HTTP request is serviced and then it should be destroyed by Spring Boot.
Upon a new request, a new instance should be created, hence there should be a unique REQUEST_ID for every request.
#Component
#Scope(WebApplicationContext.SCOPE_REQUEST)
public class RequestContext {
public RequestContext() {
putInMdc(REQUEST_ID, UUID.randomUUID().toString());
}
...
However, what we observe is lots of unrelated log messages all having the same REQUEST_ID, which can only mean that the constructor of RequestContext is not called between those requests.
All the log messages belong to the same thread ID. I know that Tomcat usually re-uses threads for multiple requests, but shouldn't Spring Boot re-create a request scoped bean anyway as soon as the request is serviced?

How does spring come to know about the new request or session?

I know in a web application, for every request it gets, spring creates a new instance of the bean in ints container.
I want to know how does spring differentiate between the requests and create new instances of bean accordingly?
This work is done by Request context listener where it takes the decision of instantiating beans based on incoming http request and discarding them once their life cycle is over. Session , Request scope beans are only relevant if the application context web aware, if otherwise IllegalStateException will be thrown.
And also refer -
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-scopes-other

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).

Categories