JMS同步请求/应答使用临时队列超时读取

时间:2013-02-15 05:05:32

标签: jms java-ee-6 glassfish-3

我目前遇到jms同步请求/回复方法的问题,这就是:

1。)ProgramA创建一个jms消息,一个临时队列并将其设置为replyTo。

2。)ProgramB拥有从ProgramA创建的消息的监听器,处理消息并回复它。但是ProgramB需要与有时需要超过10秒才能回复的第三方Web服务进行通信,这就是我设置消费者监听5000(5s)的问题,当然它会在之后超时。所以没有收到消息。

我的观察: 1.)即使ProgramA已完成阅读(尚未回复,在那一刻我尝试删除临时队列)。它无法和ProgramB仍然能够写入回复队列,但没有人会读取该消息(太晚了)。

当我尝试将5s改为20s时,问题解决了,但这是正确的方法吗?

当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;
}

2 个答案:

答案 0 :(得分:0)

这里的实际问题是您是否需要同步或异步通信。

我总是喜欢异步,从您的问题看来,在您的情况下也不需要同步通信。但是,如果存在同步的某些原因,那么您将遇到临时队列 - 您必须指定超时间隔,并且您将面临问题中表达的问题。如果程序A可以等待,则提高超时间隔,尽管这远非最佳状态。据我所知,程序B不可能检查A是否仍在监听。

在异步通信的情况下,您有(至少)两个JMS选项:

  1. 使用不同的消息队列 - 程序A在Queue1上发送消息并完成,但在Queue2上监听(例如通过消息驱动Bean),程序B在完成时发出响应。小缺点是使用一对额外的生产者和消费者。
  2. 使用相同的消息队列 - 程序A和程序B都在Queue1上发送和接收消息,但使用不同的消息选择器(请参阅说明here)。基本上,消息选择器将过滤特定侦听器的消息,从而允许使用相同的队列进行双向通信。
  3. 另见:

答案 1 :(得分:0)

您可以使用当前时间戳+ 5秒为其消息添加标头。当B收到第三方的响应时,如果当前时间大于标题,则应丢弃结果而不发送。你可以使用生存时间的jms消息属性,虽然这不是它的明确目的。