搜索

此内容没有您所选择的语言版本。

3.3. InOut Message Exchange Pattern

download PDF

Overview

Combining InOut mode with transactional JMS endpoints is problematic. In most cases, this mode of operation is fundamentally inconsistent and it is recommended that you refactor your routes to avoid this combination.

Enabling InOut mode in JMS

In a JMS consumer endpoint, InOut mode is automatically triggered by the presence of a JMSReplyTo header in an incoming JMS message. In this case, the endpoint creates an InOut exchange to hold the incoming message and it will use the JMSReplyTo queue to send the reply message.

Problems combining InOut mode with transactions

The InOut MEP is fundamentally incompatible with a route containing transactional JMS endpoints. In almost all cases, the route will hang and no reply will ever be sent. To understand why, consider the following route for processing payment requests:
from("jmstx:queue:rawPayments")
    .process(inputReformatter)
    .to("jmstx:queue:formattedPayments")
    .process(outputReformatter);
The JMS consumer endpoint, jmstx:queue:rawPayments, polls for messages, which are expected to have a JMSReplyTo header (for InOut mode). For each incoming message, a new transaction is started and an InOut exchange is created. After reformatting by the inputReformatter processor, the InOut exchange proceeds to the JMS producer endpoint, jmstx:queue:formattedPayments, which sends the message and expects to receive a reply on a temporary queue. This scenario is illustrated by Figure 3.2, “Transactional JMS Route that Processes InOut Exchanges”

Figure 3.2. Transactional JMS Route that Processes InOut Exchanges

Transactional JMS Route that Processes InOut Exchanges
The scope of the transaction includes the entire route, the request leg as well as the reply leg. The processing of the route proceeds as expected until the exchange arrives at the JMS producer endpoint, at which point the producer endpoint makes a provisional write to the outgoing request queue. At this point the route hangs: the JMS producer endpoint is waiting to receive a message from the reply queue, but the reply can never be received because the outgoing request message was only provisionally written to the request queue (and is thus invisible to the service at the other end of the queue).
It turns out that this problem is not trivial to solve. When you consider all of the ways that this scenario could fail and how to guarantee transactional integrity in all cases, it would require some substantial changes to the way that Apache Camel works. Fortunately, there is a simpler way of dealing with request/reply semantics that is already supported by Apache Camel.

Refactoring routes to avoid InOut mode

If you want to implement a transactional JMS route that has request/reply semantics, the easiest solution is to refactor your route to avoid using InOut exchanges. The basic idea is that instead of defining a single route that combines a request leg and a reply leg, you should refactor it into two routes: one for the (outbound) request leg and another for the (inbound) reply leg. For example, the payments example could be refactored into two separate routes as follows:
from("jmstx:queue:rawPaymentsIn")
    .process(inputReformatter)
    .to("jmstx:queue:formattedPaymentsIn");

from("jmstx:queue:formattedPaymentsOut")
    .process(outputReformatter)
    .to("jmstx:queue:rawPaymentsOut");
Instead of a single incoming queue, queue:rawPayments, which uses the queue from JMSReplyTo for replies, we now have a pair of queues: queue:rawPaymentsIn, for receiving incoming requests, and queue:formattedPaymentsOut, for sending outgoing replies. Instead of a single outgoing queue, queue:formattedPayments, which implicitly uses a temporary queue for replies, we now have a pair of queues: queue:formattedPaymentsOut, for forwarding outgoing requests, and queue:formattedPaymentsIn, for receiving incoming replies. This scenario is illustrated by Figure 3.3, “Pair of Transactional JMS Routes that Support Request/Reply Semantics”.

Figure 3.3. Pair of Transactional JMS Routes that Support Request/Reply Semantics

Pair of Transactional JMS Routes that Support Request/Reply Semantics

A special case

There is a special case of a transactional JMS route where you can process InOut exchanges. If you look at the preceding examples, it is clear that the essential cause of deadlock in the route is the presence of JMS producer endpoints that obey request/reply semantics. In contrast to this, if you define a route where the JMS producer endpoints obey oneway semantics (fire-and-forget), deadlock does not occur.
For example, if you want to have a route that records all of the processed exchanges in a log queue, queue:log, you could define a route like the following:
from("jmstx:queue:inOutSource")
    .to(ExchangePattern.InOnly, "jmstx:queue:log")
    .process(myProcessor);
The exchanges coming into this route are of InOut type and both the consumer endpoint, jmstx:queue:inOutSource, and the producer endpoint, jmstx:queue:log, are transactional. The key to avoiding deadlock in this case is to force the producer endpoint to operate in oneway mode, by passing the ExchangePattern.InOnly parameter to the to() command,
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.