Skip to content

Fix: Hiredis parser traps pubsub event exceptions #139

Merged
mranney merged 1 commit into
redis:masterfrom
felixge:master
Nov 14, 2011
Merged

Fix: Hiredis parser traps pubsub event exceptions #139
mranney merged 1 commit into
redis:masterfrom
felixge:master

Conversation

@felixge

@felixge felixge commented Oct 17, 2011

Copy link
Copy Markdown
Contributor

While using this module with the hiredis parser, I noticed that exceptions
thrown inside of subscribe/message/etc. callbacks would be reported as
parser error exceptions, which was confusing.

Example:

var client = require('./index').createClient();

client.on('subscribe', function() {
  throw new Error('My Error');
});
client.subscribe('channel');

I would expect the above to throw 'My Error' as a simple exception, however,
when using the hiredis parser I get:

events.js:45
        throw arguments[1]; // Unhandled 'error' event
                       ^
Error: Redis reply parser error: Error: My Error
    at RedisClient.<anonymous> (/Users/felix/code/node_redis/hiredis.js:4:9)
    at RedisClient.emit (events.js:67:17)
    at RedisClient.return_reply (/Users/felix/code/node_redis/index.js:457:22)
    at HiredisReplyParser.<anonymous> (/Users/felix/code/node_redis/index.js:220:14)
    at HiredisReplyParser.emit (events.js:64:17)
    at HiredisReplyParser.execute (/Users/felix/code/node_redis/lib/parser/hiredis.js:35:22)
    at RedisClient.on_data (/Users/felix/code/node_redis/index.js:365:27)
    at Socket.<anonymous> (/Users/felix/code/node_redis/index.js:58:14)
    ...

The attached patch fixes this problem by changing the way the HiredisReplyParser
traps exceptions, and also provides a unit test for it.

Please let me know if you need any tweaks on the patch for landing it, I was
not quite sure where to put my test / how to structure it, since most test
cases seem to be integration tests at this point.

Also, if you would prefer an integration test for this, here you go:

var client = require('./index').createClient();
var assert = require('assert');

process.on('uncaughtException', function listener(err) {
  process.removeListener('uncaughtException', listener);

  // Drop the stack, otherwise the assert gets trapped by node
  process.nextTick(function() {
    assert.ok(!/parser error/.test(err.message), err.message);
    client.quit();
  });
});

client.on('subscribe', function() {
  throw new Error('My Error');
});
client.subscribe('channel');

PS: If you wonder why this only affects pubsub events: This is because
RedisClient#return_reply does exception trapping differently for events than
it does for callbacks.

See: https://github.com/mranney/node_redis/blob/3e95c55a0301104c9cd6451d71fa5527b7797792/index.js#L431
Vs: https://github.com/mranney/node_redis/blob/3e95c55a0301104c9cd6451d71fa5527b7797792/index.js#L447

While using this module with the hiredis parser, I noticed that exceptions
thrown inside of subscribe/message/etc. callbacks would be reported as
parser error exceptions, which was confusing.

Example:

```
var client = require('./index').createClient();

client.on('subscribe', function() {
  throw new Error('My Error');
});
client.subscribe('channel');
```
I would expect the above to throw 'My Error' as a simple exception, however,
when using the hiredis parser I get:

```
events.js:45
        throw arguments[1]; // Unhandled 'error' event
                       ^
Error: Redis reply parser error: Error: My Error
    at RedisClient.<anonymous> (/Users/felix/code/node_redis/hiredis.js:4:9)
    at RedisClient.emit (events.js:67:17)
    at RedisClient.return_reply (/Users/felix/code/node_redis/index.js:457:22)
    at HiredisReplyParser.<anonymous> (/Users/felix/code/node_redis/index.js:220:14)
    at HiredisReplyParser.emit (events.js:64:17)
    at HiredisReplyParser.execute (/Users/felix/code/node_redis/lib/parser/hiredis.js:35:22)
    at RedisClient.on_data (/Users/felix/code/node_redis/index.js:365:27)
    at Socket.<anonymous> (/Users/felix/code/node_redis/index.js:58:14)
    ...
```

The attached patch fixes this problem by changing the way the HiredisReplyParser
traps exceptions, and also provides a unit test for it.

Please let me know if you need any tweaks on the patch for landing it, I was
not quite sure where to put my test / how to structure it, since most test
cases seem to be integration tests at this point.

Also, if you would prefer an integration test for this, here you go:

``` javascript
var client = require('./index').createClient();
var assert = require('assert');

process.on('uncaughtException', function listener(err) {
  process.removeListener('uncaughtException', listener);

  // Drop the stack, otherwise the assert gets trapped by node
  process.nextTick(function() {
    assert.ok(!/parser error/.test(err.message), err.message);
    client.quit();
  });
});

client.on('subscribe', function() {
  throw new Error('My Error');
});
client.subscribe('channel');
```

PS: If you wonder why this only affects pubsub events: This is because
RedisClient#return_reply does exception trapping differently for events than
it does for callbacks.

See: https://github.com/mranney/node_redis/blob/3e95c55a0301104c9cd6451d71fa5527b7797792/index.js#L431
Vs: https://github.com/mranney/node_redis/blob/3e95c55a0301104c9cd6451d71fa5527b7797792/index.js#L447
@felixge

felixge commented Oct 17, 2011

Copy link
Copy Markdown
Contributor Author

Just noticed that I used 2 spaces instead of 4 in some places, I'll fix that if you confirm the overall patch to be good.

@rmehner

rmehner commented Oct 20, 2011

Copy link
Copy Markdown

+1. Makes it way easier to debug applications that use node-redis.

@mranney

mranney commented Nov 10, 2011

Copy link
Copy Markdown
Contributor

This is a win, thanks. This will go into the next version that I'm working on now.

mranney added a commit that referenced this pull request Nov 14, 2011
Fix: Hiredis parser traps pubsub event exceptions
@mranney mranney merged commit 16c79f0 into redis:master Nov 14, 2011
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.

3 participants