Hide Forgot
Description of problem: If you create a second receiver on an exclusive queue, createReceiver() returns without throwing an exception. isValid() returns true afterwards when it is called on the session and on the receivers. However, any attempt to use the session (such as createSender()) or either receiver (such as fetch() or close()) throws a qpid::messaing::SessionError How reproducible: always Steps to Reproduce: 1. Create a connection and a session (session1) 2. Create a topic exchange ("Test.Ex") 3. qpid::messaging::Receiver receiver1 = session1.createReceiver("TestQueue;{create:always, link:{x-bindings:[{exchange:Test.EX, key:TestBinding, queue:TestQueue}], x-subscribe:{exclusive:True}}, mode:consume, node:{type:queue, x-declare:{auto-delete:True}}}"); 4. qpid::messaging::Receiver receiver2 = session1.createReceiver("TestQueue;{create:always, link:{x-bindings:[{exchange:Test.EX, key:TestBinding, queue:TestQueue}], x-subscribe:{exclusive:True}}, mode:consume, node:{type:queue, x-declare:{auto-delete:True}}}"); Actual results: session1.isValid(); //returns true receiver1.isValid(); //returns true receiver2.isValid(); //returns true receiver[1|2].[fetch|close] throws SessionError. session.create[Sender|Receiver] throws SessionError. Expected results: createReceiver() should throw (preferably), or (if that is not possible due to other constraints), since the session cannot be used anymore, isValid() should return false afterwards.
At present isValid() only refers to the validity of the handle/smart pointer. There is a separate method for checking whether the object it refers to (if it refers to any) is still error free and usable: hasError(). I accept this is a little ugly. You say that the createSender() throws SessionError in the 'actual results', and in the 'expected results' then say 'createReceiver() should throw (preferably)'. I'm confused by that. Certainly I agree that it should throw; are you saying it does not at present?
I apologize for being unclear. Expected results are that, subsequent to attempting to create the second receiver, additional calls to createReceiver (assuming they don't try to use the exclusive queue) should not throw because the first call should just fail but should not invalidate the session. Actual results are that the call to createReceiver that attempts to create the second receiver invalidates the session, causing later calls to create[Receiver|Sender] to throw. hasError() is certainly helpful, but it doesn't address the real issue: If you try to create a receiver and cannot do so because of an exclusivity conflict, it shouldn't invalidate the session, it should just fail to create the receiver.
"hasError() is certainly helpful, but it doesn't address the real issue: If you try to create a receiver and cannot do so because of an exclusivity conflict, it shouldn't invalidate the session, it should just fail to create the receiver." The issue there is that the underlying AMQP 0-10 session is invalidated (the protocol specification states this). This means that for example any unacknowledged messages sent out to consumers on that session will be requeued for redelivery. In short at present it is quite hard to make the underlying loss of the AMQP session transparent and at least leaving it invalid makes it clear that a new session needs to be created. This is an area that needs further thought however. I agree that as it is it is not ideal.
> The issue there is that the underlying AMQP 0-10 session is invalidated (the > protocol specification states this). So the spec requires the session to become invalid if an illegal action (i.e. subscribing an additional receiver to an exclusive queue) is attempted? If that's so, exclusivity does more harm than good--instead of protecting a consumer's privacy, it gives other consumers a way to continually invalidate the consumer's session.
> So the spec requires the session to become invalid if an illegal action (i.e. > subscribing an additional receiver to an exclusive queue) is attempted? Yes, in AMQP 0-10 (and earlier versions) any 'exception' renders the session invalid. Some error conditions will also render the connection invalid. The philosophy behind that decision is that exceptions/errors may leave the two peers uncertain about the conversation state and it is simplest/safest to reset. May sound good in theory, but can be inconvenient in practice and is unnecessarily harsh in many cases. > If that's so, exclusivity does more harm than good--instead of protecting a > consumer's privacy, it gives other consumers a way to continually invalidate > the consumer's session. Not really. If an exclusive subscription succeeds, that subscriber knows that only they can consume messages from the queue. If others attempt to subscribe, they will be unsuccessful. It's not intended to protect 'privacy' as such, it's intended to grant exclusive access for cases where it is important that there is only one consumer of messages (e.g. because all messages must be consumed by the same processing agent in the correct order).