New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Order matters Ack on QoS > 0 #504
Conversation
So I noticed when using orders matters, if some of the subscribred clients send messages with a Quality of Service (QoS) > 0 with slow callbacks, if you close the connexion before callbacks ends, m.Ack() will be called after the connexion has been closed, leading to sending message on a closed channel on file net.go, function 'ackFunc' line 451 for QoS 2 or line 458 for QoS1. So I moved m.Ack() outside the routine, so clients will be notified by Ack (because paho has correctly recieved the QoS ACK) it's paho's job, but ACK will send even if the callback did not finished.
I think sending ACK before processing (save to disk or anything) has finished, is clearly wrong and incorrect. This is dangerous. Messages can get lost if they are ACKed before saved. |
Thank you for your review 👍 I can't clearly imagine cases where it causes such behavior because in order matters set to false, callbacks must be called safely and goroutines starting the callbacks functions, I'm trying to reproduce such things without success. As only the sender should close a channel, never the receiver, may |
Agree with @stoxx - there are a few reasons that the call to
I do agree that you have found an issue here but would ask that you please raise it as an issue and we can have a look at the best way of handling it. Unfortunately it's likely that there will be potential downsides to all options due to the way this client is structured but I think we can come up with a solution that will avoid breaking existing uses (my current thought is that if the handler completes when the connection has gone down then the ACK should be dropped; this will lead to duplicate messages but avoiding that is difficult as the broker will automatically resend the message as soon as the connection comes up anyway; could also update the store but that may have also been closed). *Update - Sorry I was confused by "So I noticed when using orders matters"; your proposed change only applies when |
@MattBrittan thank you for your helpful explanations 👍 I'm going to write an issue, some test cases to highlight encoutered issue, and maybe some proposals. |
Thanks @thomas-tacquet; unfortunately this client is complex due to historical design decisions. This makes fixing issues like this in a way that does not break something else fairly difficult/time consuming. I made major changes for
I can see that I spotted the risk but missed the fact that Having thought about this further I think the only viable solution is going to be to drop |
Logged an issue for this so that it's visible if anyone else encounters the issue. I'll take a look at this later in the week if you have not had a chance. |
Please take a look at PR #508 and let me know your thoughts. I'm not all that happy with the approach but its the best option I could come up without a major rewrite of this section of code (and a rewrite is likely to break other things!). |
Closing this pull request because its superseded by #508; thanks very much for raising this PR. |
So I noticed when using orders matters (
OrderMatters
=false
), if some of the subscribed clients send messages with a Quality of Service (QoS) > 0 with slow callbacks, if you close the connection before callbacks ends,m.Ack()
will be called after the connection has been closed, leading to sending message on a closed channel on file net.go here :This chan is closed here : https://github.com/eclipse/paho.mqtt.golang/blob/master/client.go#L606
So I moved
m.Ack()
outside the routine, so clients will be notified by Ack (because paho has correctly received the QoS ACK) it's paho's job, but ACK sending is done even if the callback did not finished.