web-dev-qa-db-ja.com

メッセージの消費後にエラーが発生した場合、JMSメッセージキューにメッセージを保持するにはどうすればよいですか?

私のシナリオは-メッセージをキューに投稿し、メッセージが消費されたら、サードパーティのミドルウェアアプリケーションに送信します。そのミドルウェアアプリケーションがダウンしている場合、投稿されたメッセージは破棄されます。ミドルウェアアプリケーションがダウンしている場合にそのメッセージを失いたくないので、代わりに保留またはキューで待機させたいと思います。このシナリオをどのように処理するかを提案してください。

11
Dinesh M

次のようにセッションを作成する必要があります。

_Session session = connection.createSession(false,
                       Session.CLIENT_ACKNOWLEDGE);
_

サードパーティのアプリにメッセージを配信しようとすると、次のようになります。

  • それが機能している場合は、メッセージを確認する必要があります。

  • ダウンしている場合は、確認しないでください。こうすることで、JMSプロバイダーが再配信できるようになり、メッセージが失われることはありません。 message.acknowledge();

また、これを見ることができます: JMS AUTO_ACKNOWLEDGEはいつ確認されますか?

5
GionJh

JMSキューはメッセージストアではありません。

処理が引き続き失敗する「不良メッセージ」がある場合、JMSサーバー(構成されている場合)は必然的にそのメッセージを「デッドメッセージキュー」にダンプし、別のプロセスがメッセージを排出するまでゆっくりといっぱいになります。

悪いメッセージはキューをブロックする可能性があるため、キューに残したくありません(10人のコンシューマーがいて、上位10個のメッセージがすべて悪いと想像してください。したがって、すべてのプロセスは悪いメッセージに失敗し続けます-キューのストール)。

したがって、メッセージを例外シンクに格納するためのメカニズムが必要です。例外シンクでは、後で処理のためにメインキューにメッセージを挿入できます。

デッドメッセージキューはこのメカニズムではなく(JMSキューにメッセージを格納しないでください)、例外的なメッセージをより永続的なストレージ領域(つまり、dbテーブルなど)にルーティングするメカニズムである可能性があります。

そこに到達すると、それらは(自動、手動、その他何でも)精査され、再配信またはキャンセルされます。

ただし、重要な点は、このための外部メカニズムが必要であるということです。JMSサーバーだけでは、この種のメッセージに適した場所ではありません。

5
Will Hartung

これは、セッション確認応答を使用して達成できます。このために、最初にSession.AUTO_ACKNOWLEDGEを使用するようにプロデューサーコードを変更します。キューセッションの作成中に、AUTO_ACKNOWLEDGEをfalseにします。それは消費者が認めなければならないことを意味します。コンシューマーがメッセージの確認応答を送信すると、メッセージはキューから削除されます。それ以外の場合は、キューに残ります。

以下はプロデューサーコードです。

try {
        QueueConnectionFactory qcf = AppUtils.getQueueConnectionFactory(); 
        Queue q = AppUtils.getDestination();
        QueueConnection qConnection = qcf.createQueueConnection();
        QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

        QueueSender qSender = qSession.createSender(q);

        qConnection.start();
        TextMessage msg = qSession.createTextMessage("Hello");
        qSender.send(msg);

        qSender.close();
        qConnection.close();

    } catch (JMSException e) {
        // log your error to log file
        e.printStackTrace();
    }

コンシューマー側でも同じことを行う必要があり、AUTO_ACKNOWLEDGEをfalseとしてキューセッションを作成します。

メッセージを処理した後、確認応答を送信してメッセージをキューから削除できます。そうしないと、メッセージはキューに残ります。

try {
        QueueConnectionFactory qcf = getQueueConnectionFactory(); 
        Queue q = getDestination();
        QueueConnection qConnection = qcf.createQueueConnection();
        QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

        QueueReceiver qReceiver = qSession.createReceiver(q);

        qConnection.start();
        Message msg = qReceiver.receive();

  // here send your message to third party application 
  //if your third party application is down 
        if(thirdpartyapp is down){
          //here you can raise an exception 
          //or just do nothing 
          // you're not sending acknowledgement here so the msg will 
           //remain in the queue
        }else{      
          msg.acknowledge();//here youre sending ack, so msg will be deleted
          qReceiver.close();
          qConnection.close();
        }

    } catch (JMSException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
4
sri

メッセージを消費するアプリケーションがどのように設計されているかは明確ではありませんが、ローカルトランザクション内でメッセージを消費し、サードパーティのミドルウェアアプリケーションにメッセージを投稿するようにコンシューマーアプリケーションを変更することをお勧めします。投稿が成功した場合、JMSキューからメッセージを削除するトランザクションをコミットできます。アプリケーションがメッセージの投稿に失敗した場合は、トランザクションをロールバックするだけで、メッセージがJMSキューに再表示されます。そのメッセージは再び配信されます。

0
Shashi