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: 3e95c55a03/index.js (L431)
Vs: 3e95c55a03/index.js (L447)
Re-initialize the reply parser for every new connection. If a connection is terminated,
the parser could be left in a bad state. After the auto-reconnect magic kicks in, it
tries to reuse the old parser, which will not work.
This change is visible to client programs if you depend on client.reply_parser.name being
set immediately. It will now only be set after a connection is established.
Thanks to @jhurliman for reporting and @pietern for the fix suggestion.
Passing an Array as as the last argument should expand as users
expect. The old behavior was to coerce the arguments into Strings,
which did surprising things with Arrays.
* authentication retry while server is loading db (danmaz74) [GH-101]
* command arguments processing issue with arrays
New features:
* Auto update of new commands from redis.io (Dave Hoover)
* Performance improvements and backpressure controls.
* Commands now return the true/false value from the underlying socket write(s).
* Implement command_queue high water and low water for more better control of queueing.
See `examples/backpressure_drain.js` for more information.
Simply and speed up command argument processing logic.
Commands now return the true/false value from the underlying socket write(s).
Implement command_queue high water and low water for more better control of queueing.
* connection error did not properly trigger reconnection logic [GH-85]
* client.hmget(key, [val1, val2]) was not expanding properly [GH-66]
* client.quit() while in pub/sub mode would throw an error [GH-87]
* client.multi(['hmset', 'key', {foo: 'bar'}]) fails [GH-92]
I originally didn't think DISCARD would do anything here because of the clever MULTI interface, but somebody
pointed out to me that DISCARD can be used to flush the WATCH set.