3

現在、JBoss AS7 で断続的な例外が発生していますが、残念ながらまだ再現できません。

現在、基本的に JMS メッセージのプロデューサー/コンシューマーとして設定されている 2 つのアプリケーションを実行しています。デフォルトの HornetQ 設定と 5 つの MDB のプールを使用しています。

両方のアプリケーションが正常に動作し始め、期待どおりにメッセージを送受信します。しかし、しばらくすると、すべての MDB がロックされ (それぞれにメッセージが表示されますが、処理が完了しません)、その後 JBoss がハングし、10 分ごとに次のメッセージが表示されます。

[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

jarvana の JBoss コードから、セマフォを取得できない場合にこのエラーが設定されているように見えます。

 /**
 * 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 のタイムアウトを設定するその他の方法についての提案を喜んで受け入れます。

どんな助けでも大歓迎です。

御時間ありがとうございます。

編集:

そのため、MessageListener を instance-acquisition-timeout より長くスリープ状態にするだけで、最終的に問題を再現することができました。以下はテストコードです。

<!-- 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);
    }
}
}
4

2 に答える 2

3

この動作は予期されたものであり、問​​題はおそらくアプリケーションに関連しているようです。

以下に問題の概要を示します。

  1. MDB インスタンスがあります。
  2. MDB はキュー Q1 からメッセージを受信します。
  3. キュー Q1 にメッセージを送信します。
  4. MDB はそれを処理しようとしますが、instance-acquisition-timeout よりも時間がかかるプロセスをシミュレートするため、HornetQ がタイムアウトし、「X MINUTES 以内に許可を取得できませんでした」という例外が発生します。
  5. 残念ながら、MDB は処理を続行し、スリープ時間後にのみ解放されます
  6. MDB のリリース前に JBoss を停止すると、アプリケーションは処理を続行します。これは、メッセージが永続的であり、MDB#onMessage メソッドが終了していないことを認識しているためです。
  7. しかし、アプリケーションの問題を特定していないため、ロックが再び発生し、例外ループが発生します。

理想的な解決策は、MDB がロックされる理由を発見することですが、それまでは、アプリケーションが既に運用されているため、フォールバック計画が必要です。

解決策の 1 つは、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

お役に立てれば。

そして、アプリケーションの問題を検出できることを願っています。

于 2012-10-22T13:55:20.800 に答える
0

私もこの問題に遭遇し、以下のコマンドで JBoss のスレッドを確認した結果、最終的に根本原因を突き止めました。

jstack $pid

そして、スレッドのデッドロックが見つかりました。デッドロックを修正した後、JBoss は停止しなくなりました。

于 2016-10-12T02:24:20.170 に答える