Weblogic JMS 客户端 - 从单个事务中的多个队列读取
Weblogic JMS client - reading from multiple queues in single transaction
使用来自 WebLogic 11g (WebLogic Server 10.3.6.0) 的 WebLogic JMS 客户端 (wlthin3client.jar) 在单个事务中从多个 JMS 队列读取消息时遇到问题。我正在尝试从队列 Q1 中读取第一条消息,然后,如果该消息满足某些要求,则从队列 Q2 中读取其他消息(如果当时可用)。
我希望在提交事务后,两条消息都应该从 Q1 和 Q2 中消失。如果回滚 - 消息应保留在 Q1 和 Q2 中。
我的第一种方法是使用异步队列接收器从 Q1 读取,然后在需要时从 Q2 同步读取:
void run() throws JMSException, NamingException {
QueueConnectionFactory cf = (QueueConnectionFactory) ctx.lookup(connectionFactory);
// create connection and session
conn = cf.createQueueConnection();
session = conn.createQueueSession(true, Session.SESSION_TRANSACTED);
Queue q1 = (Queue) ctx.lookup(queue1);
// setup async receiver for Q1
QueueReceiver q1Receiver = session.createReceiver(q1 );
q1Receiver.setMessageListener(this);
conn.start();
// ...
// after messages are processed
conn.close();
}
@Override
public void onMessage(Message q1msg) {
try {
QueueReceiver q2receiver = session.createReceiver(queue2);
if(shouldReadFromQ2(q1msg)){
// synchronous receive from Q2
Message q2msg = q2receiver.receiveNoWait();
process(q2msg);
}
session.commit();
} catch (JMSException e) {
e.printStackTrace();
} finally {
q2receiver.close();
}
}
不幸的是,即使我发出 session.commit()
来自 Q1 的消息仍未提交。它处于 receive
状态,直到连接或接收器关闭。然后似乎在进入 delayed
状态时回滚。
其他观察:
- 如果 Q2 为空且没有可读取的内容,则 Q1 消息已正确提交。
- 当我对 Q1 和 Q2 以类似的嵌套方式使用同步 API 时,问题不会发生。所以如果我使用
q1Receiver.receiveNoWait()
一切都很好。
- 如果我以类似的嵌套方式为 Q1 和 Q2 使用异步 API,则仅调用 Q1 消息侦听器并在 Q1 上提交。但是 Q2 消息侦听器根本没有被调用并且 Q2 没有提交(消息卡在
receive
/ delayed
)。
我是不是误用了 API?或者这是一个 WLS JMS 错误?如何将多个队列的读取与异步API结合起来?
事实证明这是一个 WLS JMS bug 28637420。
错误状态表明它已修复,但我不会依赖它 - 带有此修复程序的 WLS 11g 补丁不起作用(请参阅 bug 29177370)。
Oracle 表示发生这种情况是因为两种不同的传递机制(同步消息与异步消息)并未设计为在同一会话中协同工作。
解决此问题的最简单方法是在需要在单个会话中处理多个队列的情况下使用同步 API(轮询)。我决定采用这种方法。
oracle 建议的另一个选项是将 UserTransactions 与两个不同的会话一起使用,一个会话用于异步消费者,另一个会话用于同步消费者。不过我没有测试过。
使用来自 WebLogic 11g (WebLogic Server 10.3.6.0) 的 WebLogic JMS 客户端 (wlthin3client.jar) 在单个事务中从多个 JMS 队列读取消息时遇到问题。我正在尝试从队列 Q1 中读取第一条消息,然后,如果该消息满足某些要求,则从队列 Q2 中读取其他消息(如果当时可用)。
我希望在提交事务后,两条消息都应该从 Q1 和 Q2 中消失。如果回滚 - 消息应保留在 Q1 和 Q2 中。
我的第一种方法是使用异步队列接收器从 Q1 读取,然后在需要时从 Q2 同步读取:
void run() throws JMSException, NamingException {
QueueConnectionFactory cf = (QueueConnectionFactory) ctx.lookup(connectionFactory);
// create connection and session
conn = cf.createQueueConnection();
session = conn.createQueueSession(true, Session.SESSION_TRANSACTED);
Queue q1 = (Queue) ctx.lookup(queue1);
// setup async receiver for Q1
QueueReceiver q1Receiver = session.createReceiver(q1 );
q1Receiver.setMessageListener(this);
conn.start();
// ...
// after messages are processed
conn.close();
}
@Override
public void onMessage(Message q1msg) {
try {
QueueReceiver q2receiver = session.createReceiver(queue2);
if(shouldReadFromQ2(q1msg)){
// synchronous receive from Q2
Message q2msg = q2receiver.receiveNoWait();
process(q2msg);
}
session.commit();
} catch (JMSException e) {
e.printStackTrace();
} finally {
q2receiver.close();
}
}
不幸的是,即使我发出 session.commit()
来自 Q1 的消息仍未提交。它处于 receive
状态,直到连接或接收器关闭。然后似乎在进入 delayed
状态时回滚。
其他观察:
- 如果 Q2 为空且没有可读取的内容,则 Q1 消息已正确提交。
- 当我对 Q1 和 Q2 以类似的嵌套方式使用同步 API 时,问题不会发生。所以如果我使用
q1Receiver.receiveNoWait()
一切都很好。 - 如果我以类似的嵌套方式为 Q1 和 Q2 使用异步 API,则仅调用 Q1 消息侦听器并在 Q1 上提交。但是 Q2 消息侦听器根本没有被调用并且 Q2 没有提交(消息卡在
receive
/delayed
)。
我是不是误用了 API?或者这是一个 WLS JMS 错误?如何将多个队列的读取与异步API结合起来?
事实证明这是一个 WLS JMS bug 28637420。 错误状态表明它已修复,但我不会依赖它 - 带有此修复程序的 WLS 11g 补丁不起作用(请参阅 bug 29177370)。
Oracle 表示发生这种情况是因为两种不同的传递机制(同步消息与异步消息)并未设计为在同一会话中协同工作。
解决此问题的最简单方法是在需要在单个会话中处理多个队列的情况下使用同步 API(轮询)。我决定采用这种方法。
oracle 建议的另一个选项是将 UserTransactions 与两个不同的会话一起使用,一个会话用于异步消费者,另一个会话用于同步消费者。不过我没有测试过。