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
New Feature Plan: Automatic Reconnect and Disconnected Buffering #9
Comments
James, thanks for this great writeup. Note that if the cleanSession flag is false, you do not have to re-make any subscriptions in your connectionComplete(boolean reconnect) callback I would suggest to add a parameter to the connectionComplete() to indicate the URI of the broker that was connected. The reason is that the application can specify a list of brokers on connect() call. so we want to indicate which one was connected (and the application may need to re-make subscriptions) |
As far as the buffered messages, it would be nice to have an option to rotate out the oldest, instead of throwing an exception, when the buffer is full. Of course, the application could do it by deleting the oldest (0 or 1 position?) and republishing, but the whole point here is to make the application simpler with these options. |
@marclcohen +1 for an option to rotate out the oldest when the buffer is full. |
Thanks @miketran78727, @marclcohen. Good points, I'll update the plan accordingly. |
James, great summary of the proposed changes. I have a concern about the MqttCallback interface through - is there any chance we could make it backwards compatible? I believe if we make those changes, existing applications that implement the callback won't compile. |
@kamilfb I agree that it would be problematic to existing applications, I don't think it would break binary compatibility though (Correct me if I'm wrong!). I'm not sure what we've done in the past, if it's the norm to add new methods to public APIs during a major release then we should be fine if we document it properly. If this hasn't been done before then Extending the Interface might be our only option.. |
@jpwsutton , @kamilfb Another option is to provide default methods or static methods to the existing MqttCallback interface. I prefer using default methods. In the default methods, just log the event. |
It is a good idea to provide a method to retrieve buffered message before deleting it, e.g. MqttMessage getBufferedMessage(int index) ? |
@jpwsutton What's your view on the following?
This could give us both backwards compatibility and new features. I believe making any modifications to the existing MqttCallback interface, e.g. to the connectionLost method by adding a new parameter, would break existing code. |
James,
|
When the buffer is full, the method name |
@miketran78727 Unfortunately I think default methods were only introduced in Java 8. If I remember correctly, the Java client is targeted at Java 4 and above for backwards compatibility. @kamilfb I think that's right, though I was planning on leaving @icraggs Thanks, those suggestions all sound good as well. I've updated the initial plan with all of the feedback. |
I've implemented Automatic Reconnect so far and it's available in my personal branch here: https://github.com/jpwsutton/paho.mqtt.java/commits/automatic-reconnect-offline-buffering Working on Offline Buffering now, if you spot anything odd so far let me know and I'll take a look. |
Currently only QoS 1 & 2 messages are persisted. In the case of Offline Buffering, I'm planning on persisting at least QoS 1 & 2 messages to disk, but should I persist QoS 0 messages as well? I guess the problem boils down to: At what point are we happy to say that we don't care if the message arrives or not? If we have the power to still send a message that we know has never attempted to have been sent, should we persist it? Or should we assume that if it's QoS 0 then it's loss is not an issue? |
Hello James, thank you for working on this change, makes working with Paho easier! |
I wasn't quite sure whether you meant when the client connects for the first time, or if it is trying to reconnect, so I'll summarise both: Connecting for the first timeIf the client is trying to connect for the first time i.e. your application is calling connect() then it will simply fail and not attempt to reconnect. This is because there could be many reasons for a failure to connect initially (e.g. credentials failure, or the server simply not being there) so it is simpler to assume that a failed initial connection will never be able to connect. Automatically Reconnecting after a successful initial connectIn this case, the client was connected successfully and then lost the connection. The Automatic Reconnect functionality (If enabled) will then attempt to connect after waiting one second, for every failed attempt, it will double the delay up to two minutes (1s, 2s, 4s, 8s, 16s...). Once it reaches a two minute delay, it will continue to attempt a reconnect every two minutes for forever or until the application closes the connection properly. |
I've got everything ready in Pull Request #183 including Unit Tests. Any feedback would be appreciated! |
Hi, I am developing applications for real-time use where latest data holds higher relevance , like plotting location of a mobile equipment on GIS map. Also, I would like to preserve those data which could not be received in real-time due to connection issues. If possible via separate callback method for LIFO messages. Thx |
@asutoshg This sounds like a brand new enhancement, could you raise this as a new issue please? |
@jpwsutton I have posted as new issue #327 Thx |
+1 |
Hi all, the code above |
@xchen10bu |
Automatic Reconnect and Disconnected Publishing Plan
Currently, the Paho Java client is lacking two major areas of functionality: Automatic Reconnect and Disconnected (or Offline) Publishing.
The goal is to implement these features in time for the next release Neon.
This issue aims to outline the plan for adding this new functionality into the client and has been modeled off Mike Tran's plan and work for the same functionality in the Javascript Client.
Recap: Possible Client States
There are 5 main potential states that the client can be in. The User will usually desire the client to either be in the
connected
ordisconnected
states.never connected
: This is the initial state of the client where:CONNACK
after it's initial connect request.connecting
: A connect request is in progress.connected
: The client is connected and ready to send and receive messages.disconnecting
: A disconnect request is in progress.disconnected
: The client goes fromconnected
todisconnected
state when:What does it do?
Automatic Reconnect
Will automatically attempt to reconnect to the broker (or one of the servers in the host list) while the client is in
disconnected
state.disconnected
state.connectionLost()
callback is called before the client starts the reconnect process. Since the state of the client isdisconnected
, the application is allowed to call theconnect
function with new connection options if they wish.disconnect
is called while connected, the client goes to thedisconnected
state and automatic reconnect is disabled.connect
after it had reconnected, an invalid state error will be thrown.Disconnected Publishing
Will allow the client to save messages in a buffer whilst the client is in the
disconnected
state.never connected
state. So it cannot send any messages before it connects for the first time.disconnected
state and Disconnected Publishing remains active if enabled.API Changes
Automatic Reconnect
MqttConnectOptions
class:setReconnect(boolean reconnect)
: If true, the client will attempt to reconnect when the connection is lost. Default: FalseMqttCallbackExtended
will be created which will extendMqttCallback
modifying / adding a few methods. This will be set in the existingsetCallback
method in the client:connectionComplete(boolean reconnect, String serverUri)
. This would not replace the existingIMqttToken
that you get if you callconnectWithResult
(So that we don't break any functionality). However it would serve the same purpose, it would be called every time that the client connects or reconnects to the broker. This will allow the application to re-make any subscriptions that were lost or to send any held messages if it is not using Disconnected Publishing.The
boolean reconnect
attribute is set to true if the connection was the result of an automatic reconnection, else it is false. TheString serverUri
attribute contains the URI of the server that the connection was re-made to, this is useful in scenarios where multiple server URIs are provided to theMqttConnectOptions
.reconnect()
will be added to theMqttAsyncClient
class, this will make the client attempt to reconnect straight away if in the middle of a retry interval. I'm thinking about reseting the retry interval if this is ever called with the assumption that the user knows what they're doing.cleanSession
flag is false, then any subscriptions would not have to be re-madeDisconnected Publising
DisconnectedBufferOptions
will be created with the following attributes & relevant getters and setters:disconnectedPublishing
: If true, the client will store messages whilst disconnected. Default: FalsedisconnectedBufferSize
: The maximum number of messages that will be stored in memory while the client is disconnected. Default: 5000persistDisconnectedBuffer
: If true, the client will persist the messages to disk, if false or not present, the messages will only be saved in memory. Default: FalsedeleteOldestBufferedMessages
:If true, the client will delete the 0th message in the buffer once it is full and a new message is published. Default: FalseMqttAsyncClient
class:void setDisconnectedBufferOptions
: Sets theDisconnectedBufferOptions
before a connect.int getBufferedMessagesCount
: Returns the number of messages in the buffer.MqttMessage getBufferedMessage(int index)
: Returns theMqttMessage
at the index location.void deleteBufferedMessage(int index)
: Deletes the buffered message at the index location.The following change will be made to the
MqttAsyncClient
class:publish
: Currently throws anMqttException
. If the buffer is full, this will be thrown containing a message explaining that the Message buffer is full.Sample application
Example 1
This application wants to use both Automatic Reconnect and Disconnected Publishing. The Application does not want to persist buffered messages.
Before I start work on this, I'd be very interested in hearing back from the community. Because of the very nature of the features that need to be implemented, it means adding a lot to the API which would mean a small amount of work for developers upgrading their application to use Neon (For example the addition of a callback to
MqttCallback
). If anyone can spot anything that might cause issues down the line, or thinks that there might be a better way of accomplishing this functionality please do comment!The text was updated successfully, but these errors were encountered: