Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Web Flow LockTimeoutException

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();
        }
    }
}
like image 630
Kunal Jha Avatar asked Mar 02 '12 13:03

Kunal Jha


2 Answers

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:

  • Implement a FlowExecutionListener which measures how long each request takes, and log long requests along with the flowId, stateId and transition event, this will allow you to hone in on long-running requests.
  • One good way to avoid the LockTimeoutException itself is to disable submit buttons & links using javascript once a button/link has been clicked. Obviously this doesn't solve the problem of the initial 30-second+ request.

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.

like image 200
Barry Pitman Avatar answered Oct 19 '22 12:10

Barry Pitman


Try to manipulate the timeout. Here is described how to do this https://jira.springsource.org/browse/SWF-1059. Maybe this will help you to find where the real problem is.

like image 21
Łukasz Rzeszotarski Avatar answered Oct 19 '22 11:10

Łukasz Rzeszotarski