Redis Scanner
Redis-scanner provides a way to use Redis SCAN
in Node.js either synchronously or asynchronously. In terms of compatibility, redis-scanner
is built on TravisCI after every commit using Node 0.10.x and 0.12.x. In addition to this, the latest version of io.js is also covered in these builds. Build results are submitted to Code Climate for analysis.
The current version is below v1.0.0 so the potential does exist for breaking changes, however I don't plan on doing this. This module begins as an experiment into the best way to use SCAN
. Naturally opinions of this may change over time.
Setup
redis-scanner
is available on npm, so simply install it:
$ npm install redis-scanner
Integration
You can bind the methods to your own RedisClient
instance, or you can simply create an instance of the Scanner for use.
Binding
Below is an example of binding the methods to your own RedisClient instance. This surfaces the SCAN
methods on the client by default.
var redis = require('redis');
var redis_scanner = require('redis-scanner');
var client = redis.createClient();
redis_scanner.bindScanners(client);
Once this is done, you can call any of the scanning methods. These methods can be called using either lower or upper case.
client.scan();
client.hscan();
client.sscan();
client.zscan();
Scanner
Creating an instance of Scanner for use is pretty simple:
var redis = require('redis');
var redis_scanner = require('redis-scanner');
var client = redis.createClient();
var scanner = new redis_scanner.Scanner(client, 'SCAN', key, options);
In the above case, key
is equal to the key of the object you're scanning. For SCAN
, this is simply null
.
The options
object looks like the following. Instead of providing args
you can optionally provide pattern
and count
to generate arguments internally. Do not use both.
var options1 = {
args: ['MATCH','key:*','COUNT','5'],
onData: function(result[, done]){
},
onEnd: function(err){
}
};
var options2 = {
count: '5',
pattern: 'key:*',
onData: function(result[, done]){
},
onEnd: function(err){
}
};
Scanners are reusable. Once you set one up, it will clean up after itself so it can be used again the moment onEnd
has been called (i.e. don't run the same Scanner in two places at the same time). To execute, simply call start()
on a Scanner
instance.
API
Standard API
There are two ways of using redis-scanner
, which basically just boils down to personal preference (the backend is the same). The first is designed to be typical of the existing client methods, so it blends into the existing APIs transparently. This takes the form of ([key], [args], onData, onEnd)
.
client.scan([], function(result, done){
done();
}, function(err){
});
client.scan([], function(result){
}, function(err){
});
Depending on the scanning method used, the result
argument can be either a single string or an object containing key
and value
.
'value'
{ 'key': 'field', 'value': 'value' }
Please note than SCAN
does not take a key
argument. However for the other methods HSCAN
, SSCAN
and ZSCAN
, a key must be provided. If none is provided, an error will be thrown.
client.hscan('my_hash', function(entry){
}, function(err){
});
Object API
The alternative is to simply pass all parameters within an object to the scanner. This is similar to how you would use the Scanner constructor directly as shown above.
Please note that key
is still a separate parameter when using this API. Arguments passed to onData
operate the same way as the Standard API.
client.hscan('my_hash', {
count: '5',
pattern: 'key:*',
onData: function(result[, done]){
},
onEnd: function(err){
}
});
Notes
Early Exits
Clearly you may sometimes have a need to exit before the iterator is complete (which is incidentally part of the reason why I felt the need to create this library). In this case, the remaining results are simply discarded and execution is halted. The context bound to the function provided as onData
contains an end
method which will end the processing and exit. Your onEnd
will still be called, naturally.
var count = 0;
client.scan([], function(entry){
if(++count === 5){
this.end();
}
}, function(err){
console.log(count);
});
Errors
Any errors returned from the Redis client will be passed straight to the onEnd
function and the process will be stopped. This is to avoid the case where multiple requests are timing out against the server and causing the process to hang unnecessarily.
Passing an error to the done
callback in onData
will also halt progress, and forward your err
to the onEnd
function.
client.scan([], function(entry, done){
done(new Error('Failed!');
}, function(err){
console.log(err.message);
});
Tests
Naturally, to run the tests you need Redis running. Tests operate on the default database and will wipe existing data, so be careful. Tests are controlled by Grunt.
$ npm test
$ grunt test
You can also generate coverage reports in HTML format using:
$ grunt coverage
and lcov
format using:
$ npm run lcov
Issues
If you find any issues inside this module, feel free to open an issue here.