2012-10-19 90 views
3

我目前在JBoss AS7中出现一个间歇性异常,很遗憾,我现在还不能重现。JBoss AS7在MDB锁定后挂起

我们目前正在运行两个基本上被设置为JMS消息的生产者/消费者的应用程序。我们使用默认的HornetQ配置和5个MDB池。

两个应用程序都开始正常工作,按预期发送和接收消息。但是,一段时间后,所有多边开发银行被锁定(它们每收到一条消息,但没有完成处理)和JBoss挂起一段时间后显示每隔十分钟以下消息:

[org.jboss.ejb3.invocation] (Thread-21081 (HornetQ-client-global-threads-1636833629)) JBAS014134: EJB Invocation failed on component MyMessageListener for method public abstract void javax.jms.MessageListener.onMessage(javax.jms.Message): javax.ejb.EJBException: JBAS014516: Failed to acquire a permit within 10 MINUTES 

从JBoss的代码jarvana,它似乎如果信号量无法获取,则会设置此错误:

/** 
* Get an instance without identity. 
* Can be used by finders,create-methods, and activation 
* 
* @return Context /w instance 
*/ 
public T get() { 
    try { 
     boolean acquired = semaphore.tryAcquire(timeout, timeUnit); 
     if (!acquired) 
      throw new EJBException("Failed to acquire a permit within " + timeout + " " + timeUnit); 
    } catch (InterruptedException e) { 
     throw new EJBException("Acquire semaphore was interrupted"); 
    } 
... 

问题是,为什么MDB被锁定?他们不应该超时并继续处理吗?我在standalone.xml文件中将超时设置为5分钟,但他们从来没有超时。

<session-bean> 
<stateless> 
    <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/> 
</stateless> 
<stateful default-access-timeout="5000" cache-ref="simple"/> 
<singleton default-access-timeout="5000"/> 
</session-bean> 

有谁知道会发生什么?

我也非常乐意接受有关如何模拟问题或其他方式设置MDB超时的任何建议。

任何帮助,将不胜感激。

谢谢你的时间。

编辑:

所以,我终于能够通过发送消息监听睡比实例采集超时不再是简单重现该问题。以下是测试代码:

<!-- standalone.xml --> 
<strict-max-pool name="mdb-strict-max-pool" max-pool-size="5" instance-acquisition-timeout="30" instance-acquisition-timeout-unit="SECONDS"/> 

MDB:

@MessageDriven(name = "TestMDB", activationConfig = { 
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), 
    @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/myQueue"), 
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")//, 
    }) 
public class TestMDB implements MessageListener { 

private final static Logger LOGGER = Logger.getLogger(TestMDB.class 
     .toString()); 

@Resource 
private MessageDrivenContext ctx; 

private final static int sleepingTime = MyProperties.SLEEP_MILLISECS; 

/** 
* @see MessageListener#onMessage(Message) 
*/ 
public void onMessage(Message rcvMessage) { 
    ObjectMessage msg = null; 
    Future<String> future = null; 
    MyResource res = null; 

    try { 
     if (rcvMessage instanceof ObjectMessage) { 
      msg = (ObjectMessage) rcvMessage; 
      res = (MyResource)msg.getObject(); 

      LOGGER.info("Received resource: " + res); 
      Thread.sleep(sleepingTime); 
      LOGGER.info("Released resource: " + res); 
     } else { 
      LOGGER.warning("Message of wrong type: " 
        + rcvMessage.getClass().getName()); 
     } 
    } catch (JMSException e) { 
     throw new RuntimeException(e); 
    } catch (InterruptedException e) { 
     throw new RuntimeException(e); 
    } 
} 
} 
+0

关于jboss的相关文章(未解决),https://developer.jboss.org/message/794455 – Gab

回答

3

看来,如果这种行为是可以预期的,但问题可能是应用相关的。

下面是问题的一个总结:

  1. 我们有一个MDB实例;
  2. MDB从队列Q1接收消息;
  3. 我们发送消息给队列Q1;
  4. MDB尝试处理它,但由于我们模拟了一个比实例获取超时更长的进程,HornetQ超时,我们得到了一个例外:“无法在X MINUTES中获得许可证”;
  5. 不幸的是,MDB继续处理和睡眠时间
  6. 如果我们的MDB发布之前停止JBoss的,应用程序将继续它的处理后,只有被释放,因为消息是持久的,它知道我们没有完成MDB #onMessage方法;
  7. 但是由于我们还没有确定应用程序问题,锁再次发生,我们得到一个异常循环;

理想的解决方案是发现为什么MDB被锁定,但在此之前,由于应用程序已经投入生产,我们需要一个回退计划。我相信一个解决方案是在我们到达Hornet的等待超时(或事务超时 - @ActivationConfigProperty(propertyName =“transactionTimeout”,propertyValue =“30”))后中断MDB线程,但似乎没有在JBoss AS7中做一个简单的配置(还没有)。

可悲的方法是定时执行MDB线程,并在onMessage方法中强制中断。这可以通过ExecutorService轻松实现(http://stackoverflow.com/questions/6460664/how-can-i-interrupt-method-execution-by-time)

对于遇到同样问题的任何人,我发现在网络上一些类似的讨论:

http://bryanpendleton.blogspot.com.br/2009/05/timertask-exception-handling.html https://community.jboss.org/thread/162822

希望这有助于。

并希望我可以检测到应用程序的任何错误。

+2

Isabelle,你是否设法解决了这个问题? – jguilhermemv

0

我也遇到过这个问题,最后我们通过下面的命令检查了JBoss的线程,发现了根本原因。

jstack $pid 

而我们发现一个线程死锁。在我们修复僵局之后,JBoss再也没有停下来。