Spring Web Flow LockTimeoutException

Posted

技术标签:

【中文标题】Spring Web Flow LockTimeoutException【英文标题】: 【发布时间】:2012-03-20 23:38:36 【问题描述】:

我们在 Weblogic 10 集群环境中使用 Spring Web Flow (2.0.9)。在生产中,我们得到了很多 LockTimeoutException : Unable to acquire conversation lock after 30 seconds。

我一直在试图弄清楚为什么在某些情况下只有一次点击或我们正在访问网站本身的主页时会出现上述异常。

请在 SWF 中找到试图锁定 FlowController 的代码。我不知道是锁在正在访问的 servlet 上还是其他什么?

请帮助了解在 Web 应用程序中发生此锁定时哪个资源实际上被锁定在 SWF 中?

要了解 ReentrantLock 的概念,请参考以下链接。

What is the Re-entrant lock and concept in general?

提前致谢。

异常堆栈跟踪

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)

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();
        
    

【问题讨论】:

【参考方案1】:

Spring Webflow 作为状态机运行,在可能具有关联视图的不同状态之间执行转换。多个同时执行的转换没有意义,因此 SWF 使用锁定系统来确保每个流执行(或会话)一次只处理一个 HTTP 请求

不要太拘泥于 ReentrantLock 的概念,它只是防止同一个线程等待它已经持有的锁。

在回答您的问题时,只有在请求处理期间被 Spring Webflow 锁定的流程执行(特定对话实例)。服务器仍然会处理来自其他用户的请求,甚至是来自同一用户的请求到不同的流执行。

LockTimeoutException 很难解决,因为根本问题不是抛出异常的线程。发生 LockTimeoutException 是因为另一个较早的请求花费的时间超过 30 秒,因此最好找出较早的请求花费这么长时间的原因。

疑难解答:

实现一个 FlowExecutionListener,它测量每个请求需要多长时间,并记录长请求以及 flowId、stateId 和转换事件,这将使您能够专注于长时间运行的请求。 避免 LockTimeoutException 本身的一个好方法是在单击按钮/链接后使用 javascript 禁用提交按钮和链接。显然这并不能解决最初 30 秒以上的请求问题。

您可以增加 LockTimeoutException 的超时时间,但这并不能解决实际问题,并且会导致更差的用户体验。 30 秒的请求是个问题。

最后,你提到:

我一直在试图弄清楚为什么会出现上述异常 在某些情况下,只需单击一下或我们正在访问 网站本身的主页。

我建议您尝试在浏览器的开发者工具窗口打开的情况下重新创建问题,查看“网络”选项卡,可能是后台运行的 AJAX 请求正在持有锁定。

【讨论】:

【参考方案2】:

尝试操纵超时。这里描述了如何做到这一点https://jira.springsource.org/browse/SWF-1059。也许这会帮助您找到真正的问题所在。

【讨论】:

以上是关于Spring Web Flow LockTimeoutException的主要内容,如果未能解决你的问题,请参考以下文章

草草弄完SPRING WEB-FLOW

:使用Spring Web Flow

Spring Web Flow LockTimeoutException

Spring web Flow2学习笔记

用Spring Web Flow和Terracotta搭建Web应用

Spring Web Flow 3 开发被放弃?