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

使用临时队列的JMS同步请求/应答读取超时,jms,java-ee-6,glassfish-3,Jms,Java Ee 6,Glassfish 3,我目前在jms同步请求/应答方法方面遇到问题,情况如下: 1.)ProgramA创建jms消息、临时队列并将其设置为replyTo 2.)ProgramB具有从ProgramA创建的消息的侦听器,处理消息并回复消息。但是ProgramB需要与第三方web服务通信,有时需要10秒以上的时间才能回复,这就是我设置消费者监听5000(5秒)的问题,当然之后会超时。因此没有收到该消息 我的观察: 1.)即使ProgramA已完成读取(还没有回复,此时我尝试删除临时队列)。它无法写入,ProgramB仍然

我目前在jms同步请求/应答方法方面遇到问题,情况如下:

1.)ProgramA创建jms消息、临时队列并将其设置为replyTo

2.)ProgramB具有从ProgramA创建的消息的侦听器,处理消息并回复消息。但是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;
}

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

我总是更喜欢异步,从您的问题来看,在您的情况下也不需要同步通信。但是,如果出于某种原因需要进行同步,那么您将被困在临时队列中——您必须指定超时间隔,并且您将面临问题中表达的问题。如果程序A可以等待,请提高超时时间间隔,尽管这远远不是最优的。据我所知,程序B不可能检查A是否仍在侦听

对于异步通信,您(至少)有两个JMS选项:

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


    您可以在其消息中添加一个头,其当前时间戳为+5秒。当B收到来自第三方的响应时,如果当前时间大于标头,则应删除结果而不发送。您可以使用time to live jms message属性来实现此目的,尽管这不是它的明确目的。

    Hi@Miljen,不幸的是,我一直使用synchronous,因为请求源必须尽可能多地显示响应。我只是担心我必须增加等待时间,因为第三方甚至可以在一分钟内做出响应,而当我有数百个并发用户时,这会减慢系统的速度。@czetsuya,我理解。但是,将程序保持在阻止状态仍然不会给您带来好处。我的建议:A发送带有相关ID的消息,显示进度条(或类似的东西)并完成。当程序B以准确的相关ID响应时,激活程序A,移除进度条并显示响应。否则,您将面临资源短缺的风险,因为数百个并发用户将意味着数百个线程被阻塞并等待。