1

現在、jms 同期要求/応答アプローチに問題があります。これが起こります:

1.) ProgramA は jms メッセージ、一時キューを作成し、replyTo として設定します。

2.) プログラム B には、プログラム A から作成されたメッセージに対するリスナーがあり、メッセージを処理して返信します。しかし、ProgramB はサード パーティの Web サービスと通信する必要があり、応答に 10 秒以上かかることがあります。これが問題であり、消費者が 5000 (5 秒) リッスンするように設定すると、もちろんその後タイムアウトします。したがって、メッセージは受信されません。

私の観察: 1.) ProgramA の読み取りは完了していますが (まだ応答がなく、その時点で一時キューを削除しようとしています)。それはできず、ProgramB はまだ応答キューに書き込むことができましたが、誰もそのメッセージを読み取ることはありません (遅すぎます)。

リッスン時間を 5 秒から 20 秒に変更しようとすると、問題は解決しましたが、それは正しいアプローチですか?

また、ProgramA が読み取りを停止したときに、ProgramB がキューに書き込もうとしない可能性はありますか?

部分コード:

Destination replyQueue = send(jmsUtil, actionDTO);
SalesOrderResponseDTO responseDTO = readReply(jmsUtil, replyQueue, actionDTO);

public Destination send(JmsSessionUtil jmsUtil, SalesOrderActionDTO soDTO) {
    try {
        utx.begin();        
        jmsUtil.send(soDTO, null, 0L, 1, Long.parseLong(configBean.getProperty("jms.payrequest.timetolive")), true);
        utx.commit();
        return jmsUtil.getReplyQueue();
    } catch (Exception e) {
        try {
            utx.rollback();
        } catch (Exception e1) {

        }       
    }
    return null;
}

public SalesOrderResponseDTO readReply(JmsSessionUtil jmsUtil, Destination replyQueue, SalesOrderActionDTO actionDTO) {
    SalesOrderResponseDTO responseDTO = null;
    try {       
        utx.begin();

        responseDTO = (SalesOrderResponseDTO) jmsUtil.read(replyQueue);

        if (responseDTO != null) {
            // fires the response event
            SalesOrderResponsePayload eventPayload = new SalesOrderResponsePayload();
            eventPayload.setResponseDTO(responseDTO);
            responseEvent.fire(eventPayload);
        } else { // timeout
            ((TemporaryQueue) replyQueue).delete();
            jmsUtil.dispose();
        }
        utx.commit();
        return responseDTO;
    } catch (Exception e) {
        try {
            utx.rollback();
        } catch (Exception e1) {
        }
    }
    return responseDTO;
}

public String send(MessageDTO messageDTO,
            JMSQueueEnum resultNotificationQueue, Long parentProcessId,
            int JMSPriority, long timeToLive, boolean hasReply)
            throws JMSException, InvalidDTOException, NamingException {

    try {
        // Process optional parameters
        messageDTO.setResultNotificationQueue(resultNotificationQueue);
        messageDTO.setParentProcessId(parentProcessId);

        // Wrap MessageDTO in a JMS ObjectMessage
        ObjectMessage msg = MessageDTOHelper.serialize(session, messageDTO);
        msg.setJMSType(messageDTO.getClass().getSimpleName());
        msg.setStringProperty("DTOType", messageDTO.getClass()
                .getSimpleName());

        requestProducer = session.createProducer(queue);

        if (hasReply) {
            replyQueue = session.createTemporaryQueue();
            replyConsumer = session.createConsumer(replyQueue);     
            msg.setJMSReplyTo(replyQueue);
        }

        if (JMSPriority > -1) {
            requestProducer.send(msg, DeliveryMode.PERSISTENT, JMSPriority,
                    timeToLive);
        } else {
            // Send the JMS message
            requestProducer.send(msg);
        }
        return msg.getJMSMessageID();
    } catch (Exception e) {

    }

    return null;
}

public MessageDTO read(Destination replyQueue) throws JMSException,
            NamingException {
    if (replyQueue instanceof Queue) {
        Message msg = replyConsumer.receive(20000);

        if (msg == null) {
            return null;
        }

        MessageDTO messageDTO = MessageDTOHelper
                .deserialize((ObjectMessage) msg);

        return messageDTO;
    } else {

    }
    return null;
}
4

2 に答える 2

0

現在のタイムスタンプ + 5 秒のヘッダーをメッセージに追加することができます。B がサード パーティからの応答を受信したときに、現在の時間がヘッダーよりも大きい場合、B は結果を破棄し、送信しないようにする必要があります。これには time-to-live jms メッセージ プロパティを使用できますが、それは明確な目的ではありません。

于 2013-02-15T11:46:18.393 に答える
0

ここでの実際の問題は、同期通信と非同期通信のどちらが必要かということです。

私は常に非同期を好みますが、あなたの質問から、あなたの場合も同期通信は必要ないようです。ただし、同期する何らかの理由がある場合は、一時的なキューで立ち往生しています。タイムアウト間隔を指定する必要があり、質問に記載されている問題に直面します。プログラム A が待機できる場合は、タイムアウト間隔を上げますが、これは最適とは言えません。私の知る限り、プログラム B が A がまだリッスンしているかどうかを確認する可能性はありません。

非同期通信の場合、(少なくとも) 2 つの JMS オプションがあります。

  1. 異なるメッセージ キューの使用 - プログラム A は Queue1 でメッセージを送信して終了しますが、プログラム B が完了時に応答を配置する Queue2 でリッスンします (たとえば、メッセージ駆動型 Bean を介して)。小さな欠点は、プロデューサーとコンシューマーの余分なペアを 1 つ使用することです。
  2. 同じメッセージ キューを使用する - プログラム A とプログラム B の両方が Queue1 でメッセージを送受信しますが、メッセージ セレクターが異なります (ここで説明を参照)。基本的に、メッセージセレクターは特定のリスナーのメッセージをフィルタリングするため、双方向通信に同じキューを使用できます。

以下も参照してください。

于 2013-02-15T08:41:40.757 に答える