- 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