-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Fixed resource management on manual reconnect. #734
Fixed resource management on manual reconnect. #734
Conversation
Store._inflights set to {} instead of null to prepare manual reconnect. Deferred the timing of manual reconnect calling if reconnect() called during disconnecting process. NOTE: reconnect() function usually called from 'close' or 'error' handler.
Codecov Report
@@ Coverage Diff @@
## master #734 +/- ##
==========================================
+ Coverage 92.88% 93.03% +0.14%
==========================================
Files 8 8
Lines 703 718 +15
Branches 173 178 +5
==========================================
+ Hits 653 668 +15
Misses 50 50
Continue to review full report at Codecov.
|
Defer reconnecting only the cae if during disconnecting but not disconnected yet. Added test for NOT deferring reconnect().
lib/client.js
Outdated
@@ -586,6 +586,9 @@ MqttClient.prototype.end = function (force, cb) { | |||
that.incomingStore.close(function () { | |||
that.outgoingStore.close(cb) | |||
}) | |||
if (that.deferredReconnect) { | |||
that.deferredReconnect() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as deferredReconnect
is only used internally, can you please add a _
prefix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will do it.
lib/store.js
Outdated
@@ -115,7 +115,7 @@ Store.prototype.get = function (packet, cb) { | |||
*/ | |||
Store.prototype.close = function (cb) { | |||
if (this.options.clean) { | |||
this._inflights = null | |||
this._inflights = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is generically correct. I think _we should not close store.close()
in this scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you. Store.close()
is not an appropriate point to prepare reconnect()
.
When I revert this._inflights = null
, the tests I added don't pass.
https://github.com/mqttjs/MQTT.js/pull/734/files#diff-16702ac352d8772fe21f4f9c1de7e900R2031
The connection is clean: true
(default). In this case, I think that user should be able to call client.end()
and then call client.reconnect()
in the close handler.
However, call client.reconnect()
or not is unpredictable, so I set _inflights
to {}
to prepare next client.reconnect()
calling.
I think that store.close()
should be called because client.end()
is called because of #707 (comment)
Finally, I found the appropriate point to reset Store._inflights
. It is reconnect()
function. I renew the incomingStore
and outgoingStore
there. They could be user custom object so I call constructor
explicitly.
Please check out my next commit.
Renew `Store` on reconnect instead of setting Store._inflights to `{}` on `Store.close()`.
lib/client.js
Outdated
that.deferredReconnect = null | ||
that._deferredReconnect = null | ||
that.incomingStore = new that.incomingStore.constructor(that.incomingStore.options) | ||
that.outgoingStore = new that.outgoingStore.constructor(that.outgoingStore.options) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This constructor calling might be wrong. It assumes that incomingStore
and outgoingStore
have options
, and their constructor has one parameter options
.
I considered two more approaches.
- Add a new interface like
resetInglights
toStore
. And client calls it onreconnect()
. - Add
reconnect()
method restriction. It can be called only if client is created with the optionclean: false
. User knowsclean
setting. If user want to reconnect withclean: true
, user can call newconnect()
. That means creating the new connection but it is ok forclean: true
.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approach 1 breaks existing user custom Store
implementation. So Approach 2 is good. I will remove explicit constuctor calling code and add reconnect tests for both clean: true
and clean: false
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the code using Approach 2.
Added `reconnect()` restriction to documents. Updated `reconnect()` tests. They are for `clean: false`. Added `connect()` again tests. They are for `clean: true`.
lib/client.js
Outdated
@@ -633,16 +636,27 @@ MqttClient.prototype.removeOutgoingMessage = function (mid) { | |||
} | |||
|
|||
/** | |||
* reconnect - connect again using the same options | |||
* reconnect - connect again using the same options as connect() | |||
* `incomingStore` and `outgoingStore` need to be ready before `reconnect()` calling. | |||
* | |||
* @returns {MqttClient} this - for chaining | |||
* | |||
* @api public | |||
*/ | |||
MqttClient.prototype.reconnect = function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add the two stores as an option to reconnect
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good idea!
If stores are passed, reconnect()
uses them, otherwise renew stores the same as connect()
.
If users want to reuse existing stores, hold the stores on the user side. And then, pass them to reconnect()
. It's intuitive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated.
That includes `incomingStore` and `outgoingStore` similar to `connect()`. If stores passed, `reconnect()` uses them, otherwise renew default `Store`.
Updated `reconnect()` JavaScript comment.
I forgot TypeScript update. I will do it soon. |
updated. |
Good work, landing! |
Thank you very much!! |
Store._inflights set to {} instead of null to prepare manual reconnect.
Deferred the timing of manual reconnect calling if reconnect() called
during disconnecting process.
NOTE: reconnect() function usually called from 'close' or 'error' handler.