One of the more vague points of the favored option 2 was what exactly
put/get returns, i.e. the Delivery/Tracking-Number/Whatever thing.
Once again there are two somewhat different directions we could
proceed here:
Option 1) (aka the red pill)
Delivery (or something that is 1-1 with delivery).
The delivery class is defined as part of the engine API, and thus it
quite directly follows the concept of delivery as it is formally
defined by the AMQP specification. While this class does define all
the necessary accessors to track the information that is of interest
to messenger users, it also provides a level of both access and
control that might be scary and/or downright dangerous to messenger
users. In particular delivery objects track all the runtime
communication state associated with a given delivery. As such,
deliveries are components of links as one would expect given that
the delivery-id sequence defined in the specification is scoped to a
containing link, and one can in fact navigate from a delivery oject
to its containing link, session, and connection. Given this,
returning delivery directly will pretty much provide full access to
all the internal engines used by a messenger.
A less extreme variant of this option would be to provide a facade
that internally points to the engine's delivery object but only
exposes functionality deemed safe for messenger users.
In either case the defining charactaristic of this option is that
put and get are returning an entity that directly corresponds to a
delivery.
Option 2) (aka the blue pill)
Tracking Number
Return an opaque, passive value object that can be passed back to
the messenger in order to access and/or update information about a
particular put/get.
At first I thought this was a distinction that perhaps didn't make
sense in an OO context since the "handle" pattern and the "object"
pattern in C can both easily be exposed as quite similar APIs in an
OO interface. However, upon more reflection, there is an important
distinction here even in an OO context. Intuitively a tracking
number is something that you would expect to be able to save in a
file or a database, e.g. in Java terms a tracking number might be
externalizable, whereas a delivery could not be.
It's also the case that a tracking number does not need to
correspond 1-1 with a delivery, e.g. a tracking number could be
implemented with a sequence-id and thereby allow the messenger to
answer status queries against a given "number" for an indefinitely
long period. In contrast, every delivery object has an internal
buffer for its message content, and therefore must have a defined
scope in order to conserve resources.
My inclination is to persue option 2 for the following reasons:
- Option 1 introduces more burden since users need to explicitly
manage the lifecycle of the returned objects. While this burden
might be mitigated in a garbage collected language, it would quite
likely significantly impact performance to let the GC manage
retiring these delivery objects. (The engine underneath messenger
is quite capable of cycling through hundreds of thousands of
deliveries per second, and this would most likely put a
significant burden on any GC subsystem.)
- Option 1 introduces additional action objects, the user model is
simpler if all the actions stay with messenger.
- Option 1 requires coming up with a name for something that is like
a delivery but not quite.
- Option 2 potentially offers more capabilities in terms of
persisting delivery state outside a messenger.
- Option 2 maps pretty naturally to the protocol notion of
delivery-tag and lends itself to a pretty easy name/analogy. One
option is pn_tracking_id_t, however I prefer the slightly more
abstract pn_tracker_t as it suggests a bit less about how it
might be implemented under the covers.
--Rafael