client icon indicating copy to clipboard operation
client copied to clipboard

Re-subscribing using the same topic filter - what should happen?

Open Namoshek opened this issue 3 years ago • 2 comments

This issue concerns the refactoring branch only.

After subscribing using a topic filter and a callback, it is possible to subscribe using the same arguments (or a different callback) again. What should happen in such a case? Following scenarios seem possible to me:

  1. If the QoS of the new subscription is the same as the old one, the callback of the existing subscription is replaced. No further action is taken.

  2. If the QoS of the new subscription is different from the existing subscription, we need to unsubscribe and subscribe afterwards using the new QoS. This is actually quite hard to implement in the current architecture since we could only send the first SUBSCRIBE request once we received the UNSUBACK.

  3. If the QoS of the new subscription is equal or lower to the QoS of the existing subscription, we simply add the new callback to the callback list of the subscription, so that each callback is invoked when a matching message is received.

  4. If the QoS of the new subscription is higher than the QoS of the existing subscription, we also would need to unsubscribe and subscribe again, but without removing the previous callback. This is actually a mix of options 2 and 3.

  5. We do not allow existing subscriptions to be overwritten by throwing an exception (this has been the previous behavior).

  6. One of options 1 or 3, but combined with 5 so that changing QoS is invalid.

Personally, I would prefer option 5 since it is by far the easiest solution and one would most likely not expect the library to perform complex tasks upon subscribing to the same topic again (which most likely happens by accident only anyway).

@thg2k Can you leave your opinion on this?

Namoshek avatar Aug 23 '20 07:08 Namoshek

MQTT v3.1 does not explicitly mention subscribe actions on same topic.

MQTT v3.1.1 section 3.8.4 (SUBSCRIBE) Response:

If a Server receives a SUBSCRIBE Packet containing a Topic Filter that is identical to an existing Subscription’s Topic Filter then it MUST completely replace that existing Subscription with a new Subscription. The Topic Filter in the new Subscription will be identical to that in the previous Subscription, although its maximum QoS value could be different. Any existing retained messages matching the Topic Filter MUST be re-sent, but the flow of publications MUST NOT be interrupted [MQTT-3.8.4-3].

MQTT v5.0 section 3.8.4 SUBSCRIBE Actions:

If a Server receives a SUBSCRIBE packet containing a Topic Filter that is identical to a Non‑shared Subscription’s Topic Filter for the current Session, then it MUST replace that existing Subscription with a new Subscription [MQTT-3.8.4-3]. The Topic Filter in the new Subscription will be identical to that in the previous Subscription, although its Subscription Options could be different. If the Retain Handling option is 0, any existing retained messages matching the Topic Filter MUST be re-sent, but Applicaton Messages MUST NOT be lost due to replacing the Subscription [MQTT-3.8.4-4].

One thing that needs to be factored in while making this decision is the MQTT v5.0 feature called "Subscription IDs", it allows to attach a number to each SUBSCRIBE packet that will be sent by the broker with each PUBLISH message, this helps to determine which callback should be invoked. I need to test what happens if you SUBSCRIBE to the exact same topic changing the subscription ID. My idea is that if you subscribe() again we send another SUBSCRIBE packet, but we must ensure that we do not hijack previous subscriptions.

Maybe we can try a "TDD" approach on this one, writing some specific feature tests with a few sample workflows and what we would expect, and then tune the actual behaviour of the client based on that?

thg2k avatar Aug 23 '20 10:08 thg2k

Thanks for the quotes, they are quite helpful!

One thing that needs to be factored in while making this decision is the MQTT v5.0 feature called "Subscription IDs", it allows to attach a number to each SUBSCRIBE packet that will be sent by the broker with each PUBLISH message, this helps to determine which callback should be invoked. I need to test what happens if you SUBSCRIBE to the exact same topic changing the subscription ID. My idea is that if you subscribe() again we send another SUBSCRIBE packet, but we must ensure that we do not hijack previous subscriptions.

Interesting question indeed. Based on the previous quote from the specification, I would expect that the old subscription gets removed, including the old subscription id.

Maybe we can try a "TDD" approach on this one, writing some specific feature tests with a few sample workflows and what we would expect, and then tune the actual behaviour of the client based on that?

That would still require us to define the desired behavior first. But sure, if we can get it to work in our test pipeline, I'm all for it.

Namoshek avatar Aug 23 '20 14:08 Namoshek