Skip to content
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

Merged
merged 6 commits into from
Dec 9, 2017

Conversation

redboltz
Copy link
Contributor

@redboltz redboltz commented Dec 6, 2017

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.

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
Copy link

codecov bot commented Dec 6, 2017

Codecov Report

Merging #734 into master will increase coverage by 0.14%.
The diff coverage is 100%.

Impacted file tree graph

@@            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
Impacted Files Coverage Δ
lib/client.js 96.41% <100%> (+0.11%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 13f0219...f3f781b. Read the comment docs.

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()
Copy link
Member

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?

Copy link
Contributor Author

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 = {}
Copy link
Member

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.

Copy link
Contributor Author

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)
Copy link
Contributor Author

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.

  1. Add a new interface like resetInglights to Store. And client calls it on reconnect().
  2. Add reconnect() method restriction. It can be called only if client is created with the option clean: false. User knows clean setting. If user want to reconnect with clean: true, user can call new connect(). That means creating the new connection but it is ok for clean: true.

What do you think?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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 () {
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.
@redboltz
Copy link
Contributor Author

redboltz commented Dec 7, 2017

I forgot TypeScript update. I will do it soon.

@redboltz
Copy link
Contributor Author

redboltz commented Dec 7, 2017

updated.

@mcollina
Copy link
Member

mcollina commented Dec 9, 2017

Good work, landing!

@mcollina mcollina merged commit 1eda784 into mqttjs:master Dec 9, 2017
@redboltz
Copy link
Contributor Author

redboltz commented Dec 9, 2017

Thank you very much!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants