我目前遇到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;
}
答案 0 :(得分:0)
这里的实际问题是您是否需要同步或异步通信。
我总是喜欢异步,从您的问题看来,在您的情况下也不需要同步通信。但是,如果存在同步的某些原因,那么您将遇到临时队列 - 您必须指定超时间隔,并且您将面临问题中表达的问题。如果程序A可以等待,则提高超时间隔,尽管这远非最佳状态。据我所知,程序B不可能检查A是否仍在监听。
在异步通信的情况下,您有(至少)两个JMS选项:
另见:
答案 1 :(得分:0)
您可以使用当前时间戳+ 5秒为其消息添加标头。当B收到第三方的响应时,如果当前时间大于标题,则应丢弃结果而不发送。你可以使用生存时间的jms消息属性,虽然这不是它的明确目的。