We are using Spring Web Flow (2.0.9) in the Weblogic 10 clustured environment. And in production we are getting a lot of LockTimeoutException : Unable to acquire conversation lock after 30 seconds.
I have been trying to figure out why does above exception comes in some cases when there is only a single click or we are accessing the home page of the site itself.
Please find the code which is trying to lock for FlowController in SWF. What I can't figure out is the lock is on the servlet which is being accessed or something else ?
Please help to understand in a web application when this lock occurs which resource is actually locked in SWF ?
To understand the concept of ReentrantLock , please refer to the link below.
What is the Re-entrant lock and concept in general?
Thanks in advance.
Exception Stack Trace
org.springframework.webflow.conversation.impl.LockTimeoutException: Unable to acquire conversation lock after 30 seconds
at org.springframework.webflow.conversation.impl.JdkConcurrentConversationLock.lock(JdkConcurrentConversationLock.java:44)
at org.springframework.webflow.conversation.impl.ContainedConversation.lock(ContainedConversation.java:69)
at org.springframework.webflow.execution.repository.support.ConversationBackedFlowExecutionLock.lock(ConversationBackedFlowExecutionLock.java:51)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:166)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:183)
at org.springframework.webflow.mvc.servlet.FlowController.handleRequest(FlowController.java:174)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
Lock Implementation in SWF
package org.springframework.webflow.conversation.impl;
import java.io.Serializable;
import java.util.concurrent.locks.ReentrantLock;
/**
* A conversation lock that relies on a {@link ReentrantLock} within Java 5's <code>util.concurrent.locks</code>
* package.
*
* @author Keith Donald
*/
class JdkConcurrentConversationLock implements ConversationLock, Serializable {
/**
* The lock.
*/
private ReentrantLock lock = new ReentrantLock();
public void lock() {
// ensure non-reentrant behaviour
if (!lock.isHeldByCurrentThread()) {
lock.lock();
}
}
public void unlock() {
// ensure non-reentrant behaviour
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
Spring Webflow operates as a state-machine, executing transitions between different states which might have associated views. It doesn't make sense to have multiple concurrently executing transitions, so SWF uses a locking system to make sure that each flow execution (or conversation) only handles one HTTP request at a time.
Don't get too hung up on the concept of ReentrantLock, it just prevents the same thread waiting on a lock that it already holds.
In answer to your question, it is only the flow execution (the specific conversation instance) that is locked by Spring Webflow for the duration of the request handling. The server will still handle requests from other users, or even requests from the same user to a different flow execution.
LockTimeoutException is tricky to troubleshoot because the root problem is not the thread throwing the exception. The LockTimeoutException occurs because another earlier request is taking longer than 30 seconds, so it would be a good idea to find out why the earlier request took so long.
Troubleshooting ideas:
You could increase the timeout for LockTimeoutException, but that doesn't solve the actual problem and leads to a worse user-experience. 30-second requests are the problem.
Finally, you mentioned:
I have been trying to figure out why does above exception comes in some cases when there is only a single click or we are accessing the home page of the site itself.
I suggest that you try re-create the problem with the browser's developer tools window open, watching the 'Network' tab, maybe there is an AJAX request running in the background which is holding the lock.