- From: <noah_mendelsohn@us.ibm.com>
- Date: Wed, 11 Jan 2006 18:15:33 -0500
- To: xml-dist-app@w3.org
(long note warning)
On the call today we got into an interesting discussion of req/resp vs.
fire-and-forget, which I'll abbreviate here as FAF. What I'm about to say
is pretty close to some things that David Hall and Mark Baker have said,
so I don't claim total originality, but I think this is deep and
important, and needs to be set down in detail.
I claim that req/resp is deeply different from FAF. In particular, for
reasons explained below:
a) you cannot safely support true FAF on an underlying protocol that is
req/resp (regardless, by the way, of whether that underlying protocol is
transport-like or application-like)
b) you cannot in general simulate request/response out of two FAF
messages, unless you are willing to essentially build your own req/resp
transport protocol.
===============analysis of point (a) ===================================
The main point I'd like to focus on is (a), because it's quite subtle. Why
can't we support true FAF on a request/response protocol like HTTP?
First, let me make some definitions (I'll ignore streaming in all this):
FAF: a model in which the sending application prepares a message and a
destination address, hands them to its local software for transmission,
and is then free to disappear (I.e. "forget"). In the absence of errors,
failures, unusual congestion, etc., the message is delivered intact to the
intended receiver. The receiver has no further obligation to the
protocol after reading the message. Typical application pseudo code for
this looks like:
Sender:
s = socket.new(destinationURI);
s.send(Message);
// note that client does not wait here
s.close();
Reciever:
s = socket.new(listen); // I know, this simplifies the real code
a lot
msg = s.read();
s.close();
// process the message if you like
Req/Resp: a model in which the requestor prepares a request message and
destination as for FAF, hands them to the local software for transmission,
> and waits to receive either a response or else confirmation that none
will be coming<. The responder receives the request message, processes it
an any desired manner and >MUST either transmit a response message (with
no explicit addressing) or must explicitly signal to its local software
that no response will be forthcoming.<
Client:
s = socket.new(destinationURI);
s.send(requestMessage);
// we hang on following line until the responder takes
// explicit action, either sending a response or
// an indication that none is coming
r = s.read();
s.close();
if (r != null)
processResponse(r)
else
println("No response received\n");
Responder:
s = socket.new(listen); // I know, this simplifies the real code
a lot
req = s.read();
responseMessage = processRequest(req);
if (responseMessage != null)
// note: the following response carries no address
// we assume there's an open connection left from
// the request...this will be important when
// we analyse point (b) later
s.reply(responseMessage);
// note, if no response message is sent, then the
// the following will "unexpectedly" close the socket,
// causing the client to fall through its read, but
// with no response message.
s.close();
Crucially, after sending the request, the client is waiting. For any
reasonable underlying request/response protocol, even the decision by the
responding application that no explict response message is forthcoming
(e.g. the s.close by the responder above) will trigger some sort of
signaling to the client. In the case of closing a socket in TCP/IP, I
believe that IP packets are sent to explicitly alert the other end that
the connection is being closed (I'm leaving out discussions of lost
packets and timeouts, which are very important in practice). Thus, with
request/response:
* The responder has an obligation to do >something< protocol-related after
receiving the request message.
* The client is waiting until it does.
A subtle problem occurs if you try to implement true FAF on a req/resp
protocol like HTTP. Repeating the sender code from above:
s = socket.new(destinationURI);
s.send(Message);
// note that client does not wait here
s.close();
Depending on the local implementation, I don't think the above obligates
the messaging system to even send the message. At the time of the close,
the Message might still be in a local buffer or conceivably the connection
might not yet have completed, depending on how synchronous the
implementation of the API is. The point is that typical request/response
protocols set up connections at some level. Doing so implies that client
has some state that has to be torn down >after the far end decides that
nothing more is to be done<, and that usually involves round trip
communication at some level. Round trip usually involves waiting, and FAF
is specifically the model in which the original sender does not wait.
I noticed this in DaveO's draft [1] where he failed to explicitly include
in the HTTP binding an indication of what was to happen at the point that
the server decided that it was in fact not sending back a message of any
sort. Is it to close the connection? I'm not sure that's good HTTP
practice, but it does work. Note, however, that this would NOT be the
same as fire and forget. In the req/resp model, the client MUST wait
until the connection closes or the response comes back. Fire and wait is
NOT the same as Fire and Forget.
===============analysis of point (b) ===================================
Conversely, you can't support a classic req/resp API with two FAFs, in
part because you don't know how to address the response. The responder
has an address, and the requestor uses it to address the request. The
requestor need not in general have an address. We see this all the time
in NAT'd HTTP environments. You can't model req/resp in the NAT world
very well with two FAFs, but we all routinely do request/response through
NATs. Q.E.D., I think.
================================================================
>From this I conclude that we cannot do what DaveO originally suggested,
I.e. we cannot make the response in our existing MEP truly optional. I
believe I tentatively convinced Dave of this on the phone. The plan we
agreed to explore today is indeed to make the response message mandatory,
but the response envelope optional, which is what Anish and I also
drafted.
I hope I've convinced you that true FAF would need to be a separate MEP,
as David Hull has been suggesting.
The point of this note has been to:
a) explain why making the response optional doesn't work over HTTP, and
thus why we can't or at least shouldn't try to support true FAF over HTTP.
b) explain why, if we want to support true FAF underlying transports like
UDP, then we will need a separate one-way MEP for use with them, because
they cannot do a proper job of req/resp.
I hope the above all makes sense. I do think it's important that we have
the detailed reasoning set down.
I hope this also explains why I strongly disagree with DaveO's suggestion
that SOAP should be mainly about formats and less about protocols. I
agree that separating the two is good, and we've done that. The
definition and processing of application/soap+xml is indeed quite separate
from its use in MEPs and bindings. Still for interop to work, the nodes
involved MUST know when to wait for responses, and MUST know where faults
will be delivered. That's protocols, not just formats.
Sorry the note turned out to be a bit long.
Noah
[1] http://lists.w3.org/Archives/Public/xml-dist-app/2006Jan/0007.html
--------------------------------------
Noah Mendelsohn
IBM Corporation
One Rogers Street
Cambridge, MA 02142
1-617-693-4036
--------------------------------------
Received on Wednesday, 11 January 2006 23:15:53 UTC