Gordon makes some good points. I'd like to add that I think historically a big part of the hassle isn't actually necessarily solely the API but also having to configure and manage the intermediary, and I think we need to look there as well if we want to simplify the overall pattern.
It's also worth remembering that there are significant performance benefits to keeping Message as a pure value object (i.e. a content holder) that can be reused many times even across multiple Messengers. Some of the suggestions really stray from this pattern. If I recall correctly, I think we said in prior threads that we wanted to maintain the notion of Message being a reusable content holder as an architectural invariant. Perhaps it's worth re-examining what we could do for request/response while keeping this invariant in mind. --Rafael On Fri, Jan 18, 2013 at 6:24 AM, Gordon Sim <[email protected]> wrote: > On 01/02/2013 07:14 PM, Ted Ross wrote: > >> I'd like to start a discussion on how, from an API perspective, >> applications can use the request/response pattern. If we get this >> right, we will remove a significant barrier to adoption of AMQP. >> >> Middleware messaging systems typically do a poor job of supporting this >> pattern. The Qpid APIs are quite lacking in this regard (requester >> creates and subscribes to a temporary queue with a _unique_ name and >> places this name in the reply-to field). >> >> Proton Messenger supports request/reply (see >> examples/messenger/$LANG/{**client,server}) as follows: >> >> The requester (client) has to put _something_ into the request message's >> reply_to field. It also sets the correlation_id field if it needs to >> dispatch multiple responses. The responder (server) must copy the >> request message's reply_to field to the response message's address field >> and also copy the correlation_id. >> >> This API is good for the case where the client wants the response to go >> to a third party. In this case the reply_to is well understood to be >> the address of the third party receiver. However in the more common >> case where the response is intended to come back to the client, it's not >> clear at all what to put in the reply_to field. >> >> I propose that we allow the client to simply say >> >> request_msg.reply_expected(**cid) >> > > A message has no association with a messenger (until it is put onto the > messengers outgoing queue at least). It is not clear how a method on > message would therefore be in any better position to determine the > reply-address to use. > > At present, if a message on the outgoing queue has no reply-to set, then > the messenger will automatically set the reply-to to be an address > corresponding to itself. > > You can also use the (in my view slightly clumsy) syntax ~/xyz, which will > be 'munged' into a form that prepends the messengers name to form a full > address. This form I presume would be used if you want to distinguish > different categories of replies. > > I'm not exactly enamoured with this, but it does seem at least to address > the key concern expressed here, namely what to put in the reply-to for the > simple case. (The answer being, nothing!) > > > (I added the correlation_id argument because it's almost always going to >> be needed). Further, the server could use >> >> reply_msg.in_reply_to(request_**msg) >> >> which would take care of the addresses and the correlation_id. It also >> provides a place to report an error if a request cannot be replied to >> (absent or invalid reply_to address) rather than force each server >> implementer to code this check. >> > > This is really just a short hand for: > > response.address = request.reply_to > response.correlation_id = request.correlation_id > > plus some code or exception indicating whether the address has been set. I > have no objection to such a utility, though I'm not entirely convinced that > a method on message is the best place. It also seems of fairly marginal > benefit rather than removing a 'significant barrier to adoption'. > > Have you seen the JMS solution to simplifying the request-response > pattern? There it is done by specifying a distinct class that uses a > supplied session and destination and provides a request() method that takes > a request message as input and blocks until it can return the response > message. (See http://docs.oracle.com/javaee/**1.4/api/javax/jms/** > QueueRequestor.html<http://docs.oracle.com/javaee/1.4/api/javax/jms/QueueRequestor.html>). > Details of creating temporary response queues etc are hidden behind this. I > like that general approach as it layers the functionality cleanly on top of > the more flexible base, and would also allow different configurations or > conventions to be used. > > --Gordon. > >
