Skip to content

Added error handling to imcomingStore.put callback in _handlePublish. #864

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

Merged
merged 5 commits into from
Aug 30, 2018

Conversation

redboltz
Copy link
Contributor

Added asynchronous result callback function and error handling in
_handlePubrel similar to _handlePublish.

Added asynchronous result callback function and error handling in
_handlePubrel similar to _handlePublish.
@redboltz
Copy link
Contributor Author

Store is a interface.

https://github.com/redboltz/MQTT.js/blob/master/lib/store.js always completes writing when put() is returned. But other Store might not complete writing and notify complete using callback function.

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need unit tests.

@@ -1082,12 +1085,16 @@ MqttClient.prototype._handlePubrel = function (packet, callback) {
that.incomingStore.get(packet, function (err, pub) {
if (!err && pub.cmd !== 'pubrel') {
that.emit('message', pub.topic, pub.payload, pub)
that.incomingStore.put(packet)
that.handleMessage(pub, function (err) {
that.incomingStore.put(packet, function (err) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer if we called handleMessage before sending a PUBCOMP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The updated code calls handleMessage before sending a PUBCOMP. The sequence is not changed before/after update.

lib/client.js Outdated
this.incomingStore.put(packet, function () {
this.incomingStore.put(packet, function (err) {
if (err) {
return done && done(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can done be null? If that is true, than can you please assign it to a noop function?

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'm not sure but the existing code https://github.com/mqttjs/MQTT.js/blob/master/lib/client.js#L974 cheking it. So I applied the same manner.

I've checked call sequence.
handlePublish is called only from https://github.com/mqttjs/MQTT.js/blob/master/lib/client.js#L336 in handlePacket. And handlePacket is called only from https://github.com/mqttjs/MQTT.js/blob/master/lib/client.js#L292.
At that point, nextTickWork is passed as the 2nd parameter, callback.

nextTickWork is defined https://github.com/mqttjs/MQTT.js/blob/master/lib/client.js#L283. It cannot be null.

So null checking is not required. I will remove it from my update and existing code.

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 removed done && on my environment.
Then I got errors on the following test:
https://github.com/mqttjs/MQTT.js/blob/master/test/abstract_client.js#L953

Can I remove the test?
Or revert as follows?

return done && done(err)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or

MqttClient.prototype._handlePublish = function (packet, done = function (){}) {

?

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 choose

MqttClient.prototype._handlePublish = function (packet, done = function (){}) {

Because

  1. Someone might depend on existing test. So I shouldn't remove it.
  2. You mentioned using empty function is better for empty callback at Added error handling to imcomingStore.put callback in _handlePublish. #864 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To support ES5 and older, I fixed as follows:

MqttClient.prototype._handlePublish = function (packet, done) {
  done = typeof done !== 'undefined' ? done : function () {}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 didn't notice it. I replaced it.

lib/client.js Outdated
that._sendPacket(comp, callback)
that.handleMessage(pub, function (err) {
if (err) {
return callback && callback(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please assign an empty function to callback if it's not present and remove the two checks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let me clarify. You mean

  that.incomingStore.get(packet, function (err, pub) {
    if (!err && pub.cmd !== 'pubrel') {
      that.emit('message', pub.topic, pub.payload, pub)
      that.incomingStore.put(packet, function (err) {
        if (err) {
          return callback(err)
        }
        that.handleMessage(pub, function (err) {
          if (err) {
            return callback(err)
          }
          that._sendPacket(comp, callback)
        })
      })
    } else {
      that._sendPacket(comp, callback)
    }
  })

right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I pasted wrong code.

Finally I fixed the code as follows:

MqttClient.prototype._handlePubrel = function (packet, callback) {
  callback = typeof callback !== 'undefined' ? callback : function () {}
  var mid = packet.messageId
  var that = this

  var comp = {cmd: 'pubcomp', messageId: mid}

  that.incomingStore.get(packet, function (err, pub) {
    if (!err && pub.cmd !== 'pubrel') {
      that.emit('message', pub.topic, pub.payload, pub)
      that.incomingStore.put(packet, function (err) {
        if (err) {
          return callback(err)
        }
        that.handleMessage(pub, function (err) {
          if (err) {
            return callback(err)
          }
          that._sendPacket(comp, callback)
        })
      })
    } else {
      that._sendPacket(comp, callback)
    }
  })
}

@codecov
Copy link

codecov bot commented Aug 29, 2018

Codecov Report

Merging #864 into master will increase coverage by 0.04%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master    #864      +/-   ##
=========================================
+ Coverage   94.05%   94.1%   +0.04%     
=========================================
  Files           8       8              
  Lines         757     763       +6     
  Branches      188     190       +2     
=========================================
+ Hits          712     718       +6     
  Misses         45      45
Impacted Files Coverage Δ
lib/client.js 97.46% <100%> (+0.03%) ⬆️

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 0c9cd0d...d7391a9. Read the comment docs.

@mcollina
Copy link
Member

It’s not clear what you mean. Can you pass in a custom object to add this test?

@redboltz
Copy link
Contributor Author

It’s not clear what you mean. Can you pass in a custom object to add this test?

Ok I will add test that contains cutstom Store.

Default paramter is introduced since ES6.
Replaced the way that supports older ES,
@redboltz
Copy link
Contributor Author

The original code doesn't use Store.put() callback.
https://github.com/mqttjs/MQTT.js/pull/864/files#diff-50cfa59973c04321b5da0c6da0fdf4feL1085

AsyncStore such as mqtt-level-store might take a time to complete put(). Even if so, callback give the trigger to complete.

This test check it.
https://github.com/mqttjs/MQTT.js/pull/864/files#diff-16702ac352d8772fe21f4f9c1de7e900R1038
https://github.com/mqttjs/MQTT.js/pull/864/files#diff-16702ac352d8772fe21f4f9c1de7e900R1054

AsyncStore.prototype.put = function (packet, cb) {
setTimeout(function () {
cb(new Error('Error'))
}, 200)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you shorten these? A process.nextTick might be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@redboltz
Copy link
Contributor Author

One travis-ci failed. (nodejs6)

https://travis-ci.org/mqttjs/MQTT.js/jobs/422322347#L1785

  1) MqttSecureClient
       offline messages
         should queue qos != 0 messages:
     Uncaught Error: write EPIPE
      at exports._errnoException (util.js:1020:11)
      at WriteWrap.afterWrite (net.js:806:14)

It seems that it is not related the fix.

@redboltz
Copy link
Contributor Author

I've checked all tests has been passed on my travis-ci.
https://travis-ci.org/redboltz/MQTT.js/builds/422322332

@mcollina mcollina merged commit adff840 into mqttjs:master Aug 30, 2018
@redboltz
Copy link
Contributor Author

Thank you for merging.

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