the plumbing is so weak that the application developer must provide these
mechanisms, or the plumbing may
not be universally available on all the
communicating applications, so the
applications must delve into solving
these issues. For now, let’s assume that
the plumbing is reasonably smart, and
look at the best-case behavior an application can expect.
messages, Data, and transactions
What happens when the application
has some data it is manipulating (
perhaps in a database with transactional
updates)? Consider the following options:
˲ Message consumption is recorded
before processing. This is rare because
building a predictable application is
very difficult. Sometimes the message
will be recorded as consumed, the application sets out to do the work, and
the transaction fails. When this happens, the message is effectively not delivered at all.
˲ The message is consumed as part
of the database transaction. This is
the easiest option for the application,
but it is not commonly available. All
too often, the messaging and database
systems are separate. Some systems,
such as SQL Service Broker4 provide
this option (see Figure 2). Sometimes,
the plumbing will transactionally tie
the consumption of the incoming message to changes in the application’s database and to outgoing messages. This
makes it easier for the application but
requires tight coordination between
messaging and database.
˲ The message is consumed after
figure 3. the interesting semantic occurs
as an application talks to the local
plumbing on its box.
Know it
didn’t
happen
Request
A’s Plumbing
Service-A
Don’t know
Request
Know yes
or no
Nothing beats
a plumber who
can alleviate
your worries and
make everything
“just work.” it is
especially nice
if that plumber
shares the same
understanding of
you and your needs.
processing. This is the most common
case. The application must be designed so that each and every message
is idempotent in its processing. There
is a failure window in which the work
is successfully applied to the database,
but a failure prevents the messaging
system from knowing the message was
consumed. The messaging system will
redrive the delivery of the message.
Outgoing messages are typically
queued as part of committing the processing work. They, too, may be either
tightly coupled to the database changes
or allowed to be separate. When the
database and messaging changes are
tied together with a common transaction, the consumption of the message,
the changes to the database, and the
enqueuing of outgoing messages are
all tied together in one transaction
(see Figure 2). Only after enqueuing
an outgoing message will the message
depart the sending system. Allowing it
to depart before the transaction commits may open up the possibility of the
message being sent but the transaction
aborting.
in-order Delivery:
history or Currency?
In a communication between two partners, there is a clear notion of sending
order in each direction. You may be
sending to me while I am sending to
you, meaning there is fuzziness in the
ordering for messages going past each
other, but only one message at a time is
sent in a specific direction.
A listener can easily specify that it
does not want out-of-order messages.
If you sent me n different messages in
a specific order, do I really want to see
message n– 1 when I’ve already seen
message n If the plumbing allows the
application to see this reordering, then
the application very likely has to add
some extra protocol and processing
code to cope with the craziness.
Suppose the messages always come
in order. There are two reasonable application behaviors:
˲ History (no gaps). Not only will the
messages be delivered in order, but also
the plumbing will respect the sequence
and not allow gaps. This means that
the plumbing will not deliver message
n in the dialog sequence to the app if
message n– 1 is missing. It may work to
get message n– 1 under the covers, but