MESSAGE frames after UNSUBSCRIBE

81 views
Skip to first unread message

Zteve

unread,
Mar 6, 2012, 1:03:15 PM3/6/12
to stomp...@googlegroups.com
MESSAGE frames for a subscription can arrive after an UNSUBSCRIBE is sent (due to the basic asynchronous nature of the protocol), but then trying to ACK the MESSAGE received might fail because the subscription 'no longer exists'.

If the UNSUBSCRIBE id=foo is followed by SUBSCRIBE id=foo (allowed by the spec?) then it is still possible to receive a MESSAGE frame with the id=foo, but not to know for which subscription it is intended.

I propose that once a subscription id has been used in a session, it cannot be re-used in that session.  This will mean that every MESSAGE frame received in that session has an unambiguous id reference.  UNSUBSCRIBE will still have the force it has at present, it is just that it cannot guarantee that MESSAGE frames with that id will not subsequently be received.

What do you think?

Hiram Chirino

unread,
Mar 6, 2012, 3:17:47 PM3/6/12
to stomp...@googlegroups.com
Another way to handle this: If you send the unsubscribe with receipt request, then it should be possible to guarantee that no further message will be delivered to the subscription once the receipt is sent.  

But yes I think we should highlight this case in the spec and give clients some recommendations on how to handle it.
--

Hiram Chirino

Software Fellow | FuseSource Corp.

chi...@fusesource.com | fusesource.com

skype: hiramchirino | twitter: @hiramchirino

blog: Hiram Chirino's Bit Mojo




Chris Barrow

unread,
Mar 6, 2012, 7:39:10 PM3/6/12
to stomp...@googlegroups.com, Hiram Chirino
Yes, I do think the solution here is to use receipts. That should prevent ambiguity. Any messages arriving before the UNSUBSCRIBE receipt belong to the first subscription. And no messages from the second SUBSCRIBE can arrive before its receipt. That is the rule we are following for Kaazing WebSocket Gateway. We also ensure that if SUBSCRIBE or UNSUBSCRIBE fails then the response is an ERROR frame with the subscription ID as a header so the client knows which subscription failed. I don't think there is a need to make mandatory that the second SUBSCRIBE use a different id since using receipts should solve the problem.

For ACKs, we are following a convention that UNSUBSCRIBE implicitly NACKs any unacknowledged messages. This mirrors the behavior of ActiveMQ (where MessageConsumer.close implicitly NACKs messages which have not been acknowledged).

Chris

Zteve

unread,
Mar 8, 2012, 10:08:14 AM3/8/12
to stomp...@googlegroups.com
Thank you, that shows me there may be a way for a client to avoid the problem.

I have two problems with the specification as it stands: UNSUBSCRIBE and RECEIPT.

The UNSUBSCRIBE frame specification:

The UNSUBSCRIBE frame is used to remove an existing subscription. Once the subscription is removed the STOMP connections will no longer receive messages from that destination.

This latter statement cannot be complied with unqualified because frames may 'cross in the post', as in my problem. A weaker guarantee could be asserted here, possibly referring to receipts, but see next.

The RECEIPT frame specification:

Under 'Server Frames / RECEIPT' we read:

RECEIPT frame is sent from the server to the client once a server has has successfully processed a client frame that requests a receipt.

Nowhere is "successfully processed" defined, but under 'Standard Headers / Header receipt' we read:

Any client frame other than CONNECT MAY specify a receipt header with an arbitrary value. This will cause the server to acknowledge receipt of the frame with a RECEIPT frame which contains the value of this header as the value of the receipt-id header in the RECEIPT frame.

Which implies that simple receipt is enough to trigger the RECEIPT frame.  These two sections appear to be at odds.

Unless these two problems are fixed I think the specification is insufficient to support the client circumvention of the MESSAGE following UNSUBSCRIBE problems which you advocate.

In general, if we had some clarification of what "successfully processed" means for various Client frames, it would then be possible to correctly infer the force of the receipt part of the protocol.  Since these clarifications need only specify what is and is not valid in the protocol, they need not drag in server-oriented semantics, provided they are sufficiently carefully expressed in terms of what is and is not valid in sequences of frames.

Finally, some rules about when it is possible / necessary to ACK or NACK a message, relative to the SUBSCRIBE / UNSUBSCRIBE frames should be relatively simple to express.  They could again be couched in terms of protocol frame content validity.

Thank you.

Zteve

unread,
Mar 8, 2012, 11:23:22 AM3/8/12
to stomp...@googlegroups.com, Hiram Chirino
Chris,

Thanks for your note.

For ACKs, we are following a convention that UNSUBSCRIBE implicitly NACKs any unacknowledged messages. This mirrors the behavior of ActiveMQ (where MessageConsumer.close implicitly NACKs messages which have not been acknowledged).

Of course, without the RECEIPT technique, you could still receive MESSAGEs with those ids in them after issuing UNSUBSCRIBE, and now they must be ignored, since they have been implicitly NACKed.  If the client (N)ACKs a message after issuing an UNSUBSCRIBE, it may or may not be rejected, depending upon how far through processing the UNSUBSCRIBE has got.  Finally, if the client reuses the subscription id, she still cannot tell if MESSAGES with that id can be ignored or not.

With the RECEIPT technique, this mechanism is not strictly necessary, and unless it is mandated in the STOMP spec, it would mean that clients wouldn't know if they can or cannot (N)ACK messages after UNSUBSCRIBE.  So, I would only implement this technique if the spec said we must.

RabbitMQ will redeliver all unacknowledged messages for a STOMP subscription as well.  Not identical to a NACK, necessarily, but indistinguishable from the client's point of view.  In the case of a MESSAGE frame received after an UNSUBSCRIBE, this caused us problems when the client went ahead and ACK'd it.  Hence my query.

I have raised some more questions concerning the spec in the light of the receipt solution.

Regards,
Steve Powell

Hiram Chirino

unread,
Mar 8, 2012, 11:26:26 AM3/8/12
to stomp...@googlegroups.com
Now that you better understand the intension of the spec, please feel free to fork and update the spec with the clarifications that makes sense to you.  We can then review and merge back into the next spec revision.

Zteve

unread,
Mar 8, 2012, 11:49:54 AM3/8/12
to stomp...@googlegroups.com
PS: I have just realised that (N)ACKs should not be issued for any MESSAGEs for a subscription which has been UNSUBSCRIBEd.  This is to say that in the client frames, it is not allowed to refer to a subscription id in any frame after the UNSUBSCRIBE frame for that id has been sent.  (Unless, of course, we re-SUBSCRIBE for that id, but then that has refer to the new id.)

This is a perfectly reasonable specification restriction on the protocol, which reduces the original problem to one where a re-SUBSCRIBE for a subscription id is intended, for which a RECEIPT solution is quite adequate.

Please can you add this rule to the specification, along with the note that MESSAGE frames referring to old subscription ids can be received after sending an UNSUBSCRIBE, and that they cannot be ACKed or NACKed. 

Chris Barrow

unread,
Mar 8, 2012, 12:52:13 PM3/8/12
to stomp...@googlegroups.com, Zteve, Hiram Chirino
Hi Steve,


With the RECEIPT technique, this mechanism is not strictly necessary, and unless it is mandated in the STOMP spec, it would mean that clients wouldn't know if they can or cannot (N)ACK messages after UNSUBSCRIBE.  So, I would only implement this technique if the spec said we must.
We were just trying to remove ambiguity for our own purposes about when messages get redelivered and when they can be acknowledged by the client. There are really only two ways servers can go: either redeliver unacknowledged messages on UNSUBSCRIBE or redeliver on DISCONNECT. I wasn't suggesting the STOMP specification should mandate one or the other.  I think the safest thing clients can do (in a guaranteed messaging scenario) is make sure they either ACK or NACK all the messages they received before receiving the UNSUBSCRIBE receipt. That ensures messages they do not acknowledge can immediately be redelivered and processed by someone else.

Chris

Chris Barrow

unread,
Mar 8, 2012, 1:22:33 PM3/8/12
to stomp...@googlegroups.com, Zteve
Steve,

PS: I have just realised that (N)ACKs should not be issued for any MESSAGEs for a subscription which has been UNSUBSCRIBEd.  This is to say that in the client frames, it is not allowed to refer to a subscription id in any frame after the UNSUBSCRIBE frame for that id has been sent. 
This may be too narrow (depending on what you mean by "a subscription which has been UNSUBSCRIBEd"). We have to allow for the race condition where a MESSAGE from the server "crosses in the mail" with the UNSUBSCRIBE frame from the client. Ideally the client should be able to ACK or NACK that message since the client has no way of telling at exactly what moment the server received and processed the UNSUBSCRIBE frame. If the STOMP spec stipulates the rule that the server cannot send any MESSAGE (for the subscription) after sending the unsubscribe RECEIPT then I think that should suffice to remove any ambiguities (provide receipts are used of course - if they're not then all bets are off anyway).  I guess what I'm saying is I agree with your rule provided we make it clear that "has been UNSUBSCRIBEd" means "the client has sent an UNSUBSCRIBE and has received the RECEIPT for it".

along with the note that MESSAGE frames referring to old subscription ids can be received after sending an UNSUBSCRIBE, and that they cannot be ACKed or NACKed
Same issue here. Typically we are talking about a full-duplex network connection where MESSAGE frames are potentially arriving all the time until the unsubscribe RECEIPT is received. The client does not know that what exact moment the server receives and processes the UNSUBSCRIBE, so it cannot tell which MESSAGEs cannot be ACKed or NACKed. That 's why I think we should instead state that MESSAGE frames referring to old subscription ids can be received after sending an UNSUBSCRIBE until the RECEIPT is received, and the client should be able to ACK or NACK all of those messages.

I agree it would be good to tie down in the spec the behavior for RECEIPTs. I think at the moment it's sitting on the fence a bit as to exactly what the purpose of a RECEIPT is: does it simply been "server has received the command" or does it mean "command has been successfully processed". I would be OK with going for the latter, as you were suggesting, but in that case we have to define the behavior if client is not successfully processed. I would suggest that should be to send an ERROR frame back to the client with a header giving the receipt id.

Chris
Reply all
Reply to author
Forward
0 new messages