MQTTnet
MQTTnet copied to clipboard
How to know when the ManagedMqttClient is subscribed?
Describe your question
We have a use case where I need to know when the ManagedMqttClient is subscribed to a topic after calling SubscribeAsync. I have several workarounds for the problem, such as calling SubscribeAsync on the InternalClient or waiting for a short period before continuing. But I was wondering if there is a proper way for knowing when the ManagedMqttClient has subscribed to the topic?
We need to know when we are subscribed before starting other tasks. Otherwise we end up missing messages because the ManagedMqttClient implements the operation asynchronously. It can easily be reproduced if you call PublishAsync directly after SubscribeAsync on the same topic - the message will likely be published before you are subscribed.
Which project is your question related to?
- ManagedClient
Thanks!
We hit this problem as well. The subscription isn't there when you await the SubscribeAsync which is tbh quite unexpected.
Is there any way to do correctly? Using the internal client to wait for the subscription to be processed?
I run into the same problem when trying to implement request response communication. Using the internal client is not a good option since resubscriptions after restored connection will not be handled by the managed client then. I couldn't find any way of achieving this with the managed client so I decided to make a modified version that I can use. Rather than introducing a callback for completed subscriptions, I decided to suppress sending messages whenever there are queued subscriptions that are not yet sent to the server. Then I can just call publish directly after subscribe knowing that the subscription will be active when the message is actually published.
I put the code here if anyone is interested.
I did a hybrid apporach. I can't share the code but we did the following:
Wrap the IManagedMqttClient in your own IMqttClient interface with the necessary methods (Connect, Disconnect, Subscribe, Publish).
For Connect use a TaskCompletionSource to only complete after the IManagedClient has connected successfully.
For Subscribe we used the IManagaedMqttClient.Internal and subscribes twice to the topic we want. According to the MQTT spec (and our testing) this does not harm but with Internal Async stuff only completes after it was successful and not just queued.
Hth
I guess that with that approach you lose the ability to have subscriptions being queued and sent when reconnected if you temporarily lost connection after connecting the first time. But if you are on a stable enough network to not consider that a problem that seems like a simple solution. I didn't think of the possibility to subscribe twice.
No I don't lose the ability for auto-resubscription. Our Subscribe implementation first triggers the subscription via the Internal client and after that with the managed client to keep the auto-resubscription feature. That's the reason why I subscribe twice to the same topic.
Yes, but if you are disconnected when you call subscribe? I have only been using the managed client, but I would assume the internal client would fail and return an error somehow. The managed client would queue the subscription and send it a when it is connected again. I guess that is why you let Connect wait for the managed client to connect before completing the task, but you could get disconnected again later.
Ah, good point. Yes it will fail at that time. But I think the exception is better than "queuing" the subscribe while you expect to be subscribed after awaiting that call. But you could just not use the Internal in that case and only queue the subscribe.
I would say this is quite unexpected and dangerous behavior. Asyncness of the method suggests that it returns once subscription is made, but as we see that's not the case and users can easily lose messages, without any clean options to handle this situation. I would label this as a bug, rather than a question.
From my point of view it's a bug. Or we should have a way to know from IManagedMqttClient the status of the subscriptions.
I don't see what's the point of subscribing when offline: queuing SUB packets, replay when online, and then inform of SUBACKS, seems like very complex with little benefit.
I'd say the managed client should not expose SubscribeAsync, in favor of using the internal client to subscribe.