In a load-balanced server environment,
the two retries may land at different
back-end servers and be processed independently.
From the sender’s perspective, the
application tosses a message into the
plumbing with some name that hopefully will get it to the desired partner.
Until you hear a response, you cannot
tell if the message was received, the
message was lost, the response was
lost, or the work is still in progress. The
request must be idempotent (see Figure 8).
The first message sent to a service
must be idempotent because it may be
retried in order to cope with transmission failures. Subsequent messages can
count on some plumbing to help (
provided that the application runs on top
of the plumbing). After the first message, the plumbing can know enough
about the destination of the message
(in a scalable system) to perform automatic duplicate elimination. During
the processing of the first message, the
retries may land in different portions of
the scalable service, and then automatic duplicate elimination is not possible.
Sometimes a server receives the
first message (or messages) from a dia-
log, then a retry of the message (or se-
quence of messages) is rerouted to an-
other server in the load-balanced pool.
This can go awry in two ways:
1. A sequence of messages ( 1, 2, and
3) is sent to service Foo, and the load-balancer selects Foo A.
2. The work for the messages is performed at Foo A.
3. The answer is sent back indicating
future messages should target Foo A as
a resolved name. Unfortunately, the
reply is lost by the flaky network transport.
4. A retry to service Foo happens, and
the messages are sent to server Foo N.
5. The work for messages 1, 2, and 3
is performed at server Foo N.
6. The response is sent back to the
initiator who now knows to keep chatting with Foo N.
Somehow, we must ensure the redundant work performed at Foo A is not
a problem.
figure 10. An application knows the initiation-stage has completed when it hears from
the partner.
Initiator’s Plumbing
Initiating
Service
Message
Message
Message
Messages
are sent
but none
received
Initiation
The receipt of a message from
the target will definitively end
the initiation stage...
figure 11. the last messages sent in the same direction cannot be guaranteed.
Request-
Response
Fire-And-
Forget
Service-A
Service-B
Service-A
Service-B
Service-A
Service-B
Service-A
Service-B
Accurately ending the
initiation stage
An application knows it has reached a
specific partner when a message is returned from its local plumbing. If the
other service has responded on the
dialog, then there is a specific server
or a bound session state for the dialog.
While the application may not directly
see the binding to the specific resources in the partner, they must have been
connected by the time an application
response is seen.
Prior to the application’s receipt of
a partner application’s message from
its local plumbing, any message that is
sent will possibly be rerouted to a new
(and forgetful) implementation of the
partner.
Only after you have heard from the
application on the other side may you
exit the initiation stage of the dialog
(see Figure 10). An application can see
only what its plumbing shows it. When
an app starts sending messages to its
partner, it has the initiation-stage ambiguity and must ensure that all messages have a semantic for idempotent
processing. When the local plumbing
returns a message from the partner, the
local application can be assured that
the plumbing has resolved the initiation-stage ambiguity and now messages can be sent without having to ensure
that they are idempotent.
Not Guaranteed
Not Guaranteed
Not Guaranteed
Not Guaranteed
Guaranteeing idempotence
of the first messages
Everything you say as an application in