Our portlets keep state in the HttpSession, which is shared by all request processing threads for the same session.
The portlet spec (JSR-168) writes:
PLT.5.2.4.3 Multithreading Issues During Request Handling
The portlet container handles concurrent requests to the same portlet by concurrent
execution of the request handling methods on different threads. Portlet developers must
design their portlets to handle concurrent execution from multiple threads from within the
processAction and render methods at any particular time.
I wonder how I am supposed to achieve that? Sure, I can use synchronization to achieve mutual exclusion during both processAction and render, but I don't see how I can enforce atomicity of request processing as a whole. In particular, I worry about the following scenario:
Thread 1 executes processAction, loading data into the session for later rendering
Thread 2 executes processAction, discarding that data from the session
Thread 1 executes render, reading the data to render from the session, and throws a NullPointerException because the prepared data is no longer there ...
How is that scenario usually prevented? In particular, when using the JBoss portlet bridge to adapt JSF to a Portlet environment?
I'd say that if there are two portlets operating on the same data, especially one reading it while the other deletes it, there's most likely a serious flaw in the design.
You might then want to store the data per portlet/thread, i.e. if portlet1 reads some data you should write lock it until reading is finished and put it into the session using a unique key.
If it is legal to delete data that should be rendered, then you should account for that and check again during render.
Related
I got a doubt about threadlocal usage in managing sessions. It is..
In Thread Local, which ever thread that creates the thread local object has the access to that session object, and only that thread can modify the session object data. There might be many threads running to complete a single user request.
So what about all other threads that participate to complete one user request.
They wont get access to modify the session object, as whichever thread creates the Thread local object gets its own session object, so other threads that run to complete a single user request might not update their data to the session object to which they actually wanted to.
I mean if thread-1 and thread-2 participate in completing a user request, but thread-1 comes to create the threadlocal object, and thread-2 executes other codes as part of the request, but after thread-2 completion , it cant update the session data because, only tharead-1 has access to the session as it has created the threadlocal object.
So how are we resolving this issue.
Are we making sure that only one thread participate in completeing single users request ? or
How are we so sure that which ever thread that creates the threadlocal object is only coming to update the session data associated for that request ?
Well first, RTS (Real-time system) have to be distinguished from high performance systems. In RTS time has been split in frames and piece of software have one or more frame allocated to them. Which makes very predictable which task system is performing at a given time and also which other tasks are running in parallel. Thus design help in avoiding/limiting concurrency management.
Second, high performance systems (whatever RTS or not) don't necessarly rely on multithreading for the exact same reason as for RTS : concurrency management and blocking structures more precisely are bottlenecks. And multithreading is not the only solution for parallel processing. Forks, grid computing and forth work greats and offer more scalability, stability, robustness, etc.
So, single thread environments are generally based on an async design. You split your work (ie request processing) in small non-waiting/blocking structures. All waiting/blocking (or even agressive long computing) are sent "somewhere" and just notify request processor when complete. In this case one thread can treat many request during a single request processing (not sure to be clear at this point ...)
In such (and some other) cases, you can't use thread-local binding. However, you can use "local scope" to share a reference across your processing :
Map<String, String> context = new LinkedHashMap<>();
context.put("id", "42");
taskQueue.add(() -> context.put("state", "action1"));
taskQueue.add(() -> System.out.printf("%-10s > state=%s%n", context.get("id"), context.get("state")));
(assuming taskQueue is Queue of Runnable)
You can also save request context by:
generating a "Unique Request Identifier" (suitable class should be UUID)
using a request context storage (can be a simple ConcurrentMap) or more advanced storage such as Key-Value Cache, Key-Value Store or Document store.
attaching "Unique Request Identifier" to all request-bound actions
I need to run some time-consuming task from a controller. To do it I have implemented an #Async method in my service so that the controller can return immediately (for example with 202 Created status).
The problem is that the task need access to some session-scoped beans. With this approach I am getting org.springframework.beans.factory.BeanCreationException: Error creating bean with name (...): Scope 'session' is not active for the current thread (...).
The same result is when I manually create an ExecutionService instead of #Async.
Is it possible to somehow make a worker thread attached to the current session?
EDIT
The purpose is to implement a bulk operation, providing a way to monitor the status of processing. Something like described in this answer: https://stackoverflow.com/a/28787774/718590
If I run it synchronously, there will be no indication of the status (how many items processed), and a request timeout may occur.
If I correctly understand, you want to be able to start a long time asynchronous processing from a spring web application, and be able to follow advancement of processing from the session that started it. And the processing could use beans contained in the session.
For a good separation of concerns, I would never have an asynchronous thread know a session. The session is related to HTTP and can be destroyed at any time before the thread can finish (or even begin in race conditions) its processing.
IMHO, a correct design would be to create a class containing all the informations shared between the web part and the asynchronous processing : the status (whatever it can be), the user that started processing if is is relevant and every other relevant piece of information. In your controller (of preferently in the service method called by the controller) you prepare an object of that class, and pass it to the #Async method. Then before returning, the controller stores the object in session. That way :
the asynchronous processing has all its required information, even is the session is destroyed later. It does not need to know the session and only cares for its processing and updates its status
the session of the web application knows that the asynchronous processing is running, know how it was started and what is the current status
It can be adapted to your real problem, but this should meet your requirements.
When working on an ASP.NET application, I discovered that placing something in the session cache, or really, accessing variables in the session cache, caused my Ajax queries to stop being asynchronous. I learned that this was because the session basically blocks - if I fire two Ajax requests from my browser at the same time, and the first one takes a bit to return, the session is locked in the first request until that request is completed, at which point my second Ajax request starts working.
In PHP I gather that there is an option to close the session for writing (and / or open it in a read-only way) so that session variable access is non blocking and things stay asynchronous.
I'm building an application that will be Java, probably running on Tomcat (though I could change to some other container if I needed) and I am not able to find out whether Java has the same issue (session variable reads block) or has the same remedy (early close, read only mode). Has anyone encountered that issue before?
In Tomcat, HttpSession is implemented in org.apache.catalina.session.StandardSession (source here).
If you look at the source, you will see that calls to HttpSession.getAttribute(String) and HttpSession.setAttribute(String, Object) are pretty much channelled to a ConcurrentHashMap without any additional synchronization.
This means that these calls derive the contract of ConcurrentHashMap. Quoting its Javadoc:
retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access. <..> Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove)
The table is internally partitioned to try to permit the indicated number of concurrent updates without contention. Because placement in hash tables is essentially random, the actual concurrency will vary.
It looks like blocking takes place because of threads synchronization of access to HttpSession as described in this SO answer
So, it must be that 2nd request is blocked only while 1st one is working with HttpSession (or if you have some shared lock which is held for long time by 1st request, but this has nothing to do with Tomcat).
Since this synch is required by Servlets spec, you shouldn't try to violate it. Instead, make your app so it minimizes time it needs to read from or write to HttpSession.
Additionally, as I wrote above, blocking may occur if you have additional lock which makes several requests execute sequentially. Try to make several thread dumps of Tomcat when you have sent 2nd request to Tomcat and see if there's any such lock which is waited by 2nd requet for.
Is it possible, that a session-scoped backing bean is accessed by multiple threads at the same time?
The servlet spec says, it is possible:
Multiple servlets executing request threads may have active access to the same
session object at the same time. The container must ensure that manipulation of
internal data structures representing the session attributes is performed in a thread
safe manner. The Developer has the responsibility for thread safe access to the
attribute objects themselves. This will protect the attribute collection inside the
HttpSession object from concurrent access, eliminating the opportunity for an
application to cause that collection to become corrupted.
However I could not make the server (JBoss) use different threads for the same session. When I opened multiple tabs and started a long running request in one tab, and then started a request in another tab, the second tab had to wait for a response until the action started in the first tab was completed.
I also verified this by blocking the thread with a breakpoint in the backing bean. It was not possible to do anything in other tabs of the same session until I resumed the thread.
Despite this we have some strange exceptions in the production log and so far the only possible explanation we have is, that multiple threads concurrently access the same session-scoped backing bean.
Yes, A Servlet session is thread safe. But, if you are putting mutable object in the session. The application should take care of the synchronization.
In your case, if your Bean is Mutable i.e, has state. Yes it has to be thread safe.
And about your test case, it depends on the browser you are using. Most browsers support upto 6 connections in parallel for every server. But, Not sure if they use parallel connections if there have cookies.
From the javadoc for Session it states:
A Session object is a single-threaded context for producing and consuming messages.
So I understand that you shouldn't use a Session object from two different threads at the same time. What I'm unclear on is if you could use the Session object (or children such as a Queue) from a different thread than the one it created.
In the case I'm working on, I'm considering putting my Session objects into a pool of available sessions that any thread could borrow from, use, and return to the pool when it is finished with it.
Is this kosher?
(Using ActiveMQ BTW, if that impacts the answer at all.)
I think the footnote from section 4.4 in the JMS 1.1 spec sheds some light:
There are no restrictions on the number of threads that can use a Session object or those it creates. The restriction is that the resources of a Session should not be used concurrently by multiple threads. It is up to the user to insure that this concurrency restriction is met. The simplest way to do this is to use one thread. In the case of asynchronous delivery, use one thread for setup in stopped mode and then start asynchronous delivery. In more complex cases the user must provide explicit synchronization.
By my reading of the spec what you want to do is OK, provided you correctly manage concurrency.
Sadly the JMS docs are often not written as clearly or precisely as we might like :o(
But reading the spec I'm now pretty convinced you really shouldn't access the session from other threads, even if you guarantee there's no concurrent access. The bit of the javadoc that swung it for me was:
Once a connection has been started,
any session with a registered message
listener(s) is dedicated to the thread
of control that delivers messages to
it. It is erroneous for client code to
use this session or any of its
constituent objects from another
thread of control. The only exception
to this is the use of the session or
connection close method.
Note the clear use of 'thread of control' and the singling out of 'close()' as the only exception.
They seem to be saying that even if you're using asynchronous message consumption (i.e. setMessageListener) - which means you get called back on another thread created by JMS to receive messages - you're never allowed to touch the session or related objects again from any other thread, because the session is now 'dedicated' to the JMS delivery thread. For example, I assume this means you couldn't even call message.acknowledge() from another thread.
Having said that, I only just noticed that we haven't been obeying this constraint, and have yet to notice any ill effects (using SonicMQ). But of course if you don't obey the standard, all bets are off, so I guess we need to obey the 1-thread 1-session rule to stay safe.