Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

redis-fast-driver

h0x91b1.2kMIT2.2.6TypeScript support: included

Fast truly async driver for redis (based on hiredis async version)

redis, async, pipelining

readme

Redis-fast-driver

Truly async redis driver designed for maximum performance. Extremely simple, extremely fast.

This node module uses the hiredis async library for connection and parsing written in C by Salvatore Sanfilippo.

All redis commands including PUB/SUB and MONITOR work. This driver has been in use for two years on my production environment under extremely high loads (30k ops/sec per redis per cluster). This driver is also used in https://github.com/joaojeronimo/node_redis_cluster and in my fork https://github.com/h0x91b/fast-redis-cluster

Build Status

Installing

npm install redis-fast-driver --save

Usage

Check example*.js for usage.

var Redis = require('redis-fast-driver');

var r = new Redis({
    //host: '/tmp/redis.sock', //unix domain
    host: '127.0.0.1', //can be IP or hostname
    port: 6379,
    maxRetries: 10, //reconnect retries, default -1 (infinity)
    auth: '123', //optional password, if needed
    db: 5, //optional db selection
    autoConnect: true, //will connect after creation
    doNotSetClientName: false, //will set connection name (you can see current connections by running CLIENT LIST on the redis server)
    doNotRunQuitOnEnd: false, //when you call `end()`, driver attempts to send `QUIT` command to redis before actual end
    // If a connection failure occurs, this is the time to wait before initiating a reconnect
    reconnectTimeout: 1000,
    // Amount of time to wait for an initial connection to be successful before trying again
    connectTimeout: 5000,
});

//happens only once
r.on('ready', function(){
    console.log('redis ready');
});

//happens every time it connects
r.on('connect', function(){
    console.log('redis connected');
});

r.on('disconnect', function(){
    console.log('redis disconnected');
});

r.on('reconnecting', function(num){
    console.log('redis reconnecting with attempt #' + num);
});

r.on('error', function(e){
    console.log('redis error', e);
});

// called on an explicit end, or exhausted reconnections
r.on('end', function() {
    console.log('redis closed');
});

//rawCall function has 2 arguments,
//1 - an array which contain a redis command
//2 - an optional callback
//Redis command is case insesitive, e.g. you can specify HMGET as HMGET, hmget or HmGeT
//but keys and value are case sensitive, foo, Foo, FoO are not the same...
r.rawCall(['set', 'foo', 'bar'], function(err, resp){
    console.log('SET via rawCall command returns err: %s, resp: %s', err, resp);
});

r.rawCall(['ping'], function(e, resp){
    console.log('ping', e, resp);
});

// Also has built-in ES6 Promise support (at the cost of a performance hit)
r.rawCallAsync(['ping'])
.then((resp) => {
    console.log('ping', resp);
})
.catch((e) => {
    console.error(e);
});

//types are decoded exactly as redis returns them
//e.g. GET will return string
r.rawCall(['set', 'number', 123]);
r.rawCall(['get', 'number'], function(err, resp){
    //type of "resp" will be "string"
    //this is not related to driver this is normal redis behaviour...
    console.log('The value: "%s", number key becomes typeof %s', resp, typeof resp);
});

//but the INCR command on the same key will return a number
r.rawCall(['incr', 'number'], function(err, resp){
    //type of "resp" will be a "number"
    console.log('The value after INCR: "%s", number key becomes typeof %s', resp, typeof resp);
});
//"number" type will also be returned on INCRBY ZSCORE HLEN and on each other redis command which returns a number.

//ZRANGE will return an Array, same as redis.
r.rawCall(['zadd', 'sortedset', 1, 'a', 2, 'b', 3, 'c']);
r.rawCall(['zrange', 'sortedset', 0, -1], function(err, resp){
    //type of will be "number"
    console.log('JSON encoded value of zrange: %s', JSON.stringify(resp));
});

//SCAN, HSCAN, SSCAN and other *SCAN* commands will return an Array within Array, like this:
// [ 245, ['key1', 'key2', 'key3'] ]
// first entry (245) - cursor, second entry - Array of keys.
r.rawCall(['hscan', 'hset:1', 0], function(e, resp){
    console.log('hscan 0', e, resp);
});

r.rawCall(['hmset', 'hset:1', 'a', 1, 'b', 2, 'c', 3], function(e, resp){
    console.log('hmset', e, resp);
});

r.rawCall(['zadd', 'zset:1', 1, 'a', 2, 'b', 3, 'c', 4, 'd'], function(e, resp){
    console.log('zset', e, resp);
});

//HMGET and HGETALL also return an Array
r.rawCall(['hgetall', 'hset:1'], function(e, resp){
    console.log('HGETALL', e, resp);
});

r.rawCall(['zrange', 'zset:1', 0, -1], function(e, resp){
    console.log('ZRANGE', e, resp);
    //disconnect
    r.end();
});
`

Speed

Works MUCH faster then node-redis, 20-50% faster then ioredis and even faster then the redis-benchmark tool.

Results for my MacBook Pro (Retina, 15-inch, Mid 2014, 2.5 GHz Intel Core i7) via tcp/ip.

Redis benchmark tool with -q flag via tcp/ip on this machine:

PING_INLINE: 85324.23 requests per second
PING_BULK: 85034.02 requests per second
SET: 85034.02 requests per second
GET: 84317.03 requests per second
INCR: 87032.20 requests per second
LPUSH: 85397.09 requests per second
RPUSH: 86505.19 requests per second
LPOP: 85106.38 requests per second
RPOP: 84961.77 requests per second
SADD: 86132.64 requests per second
HSET: 86058.52 requests per second
SPOP: 86430.43 requests per second
LPUSH (needed to benchmark LRANGE): 84817.64 requests per second
LRANGE_100 (first 100 elements): 26441.04 requests per second
LRANGE_300 (first 300 elements): 11273.96 requests per second
LRANGE_500 (first 450 elements): 7881.46 requests per second
LRANGE_600 (first 600 elements): 6071.28 requests per second
MSET (10 keys): 78064.01 requests per second

Mocha test (npm run bench you will need to install npm i matcha before, excluded it because of security alerts) of Redis-fast-driver:

==========================
redis-fast-driver: 2.1.2
CPU: 8
OS: darwin x64
node version: v8.9.4
current commit: 7694b0d
==========================

Concurrency 10000
475,043 op/s » PING
358,870 op/s » SET foo bar
406,564 op/s » GET foo
437,724 op/s » INCR number
185,442 op/s » HGETALL hset:1
181,277 op/s » ZRANGE zset:1 0 5
17,493 op/s » LRANGE list 0 99

Concurrency 1000
368,027 op/s » PING
294,628 op/s » SET foo bar
314,100 op/s » GET foo
345,316 op/s » INCR number
155,711 op/s » HGETALL hset:1
158,416 op/s » ZRANGE zset:1 0 5
16,769 op/s » LRANGE list 0 99

Concurrency 500
364,537 op/s » PING
254,194 op/s » SET foo bar
297,171 op/s » GET foo
310,571 op/s » INCR number
142,677 op/s » HGETALL hset:1
143,808 op/s » ZRANGE zset:1 0 5
16,230 op/s » LRANGE list 0 99

Concurrency 250
343,095 op/s » PING
242,263 op/s » SET foo bar
280,271 op/s » GET foo
293,171 op/s » INCR number
141,413 op/s » HGETALL hset:1
135,673 op/s » ZRANGE zset:1 0 5
15,667 op/s » LRANGE list 0 99

Concurrency 100
293,601 op/s » PING
213,687 op/s » SET foo bar
245,684 op/s » GET foo
254,148 op/s » INCR number
126,322 op/s » HGETALL hset:1
121,123 op/s » ZRANGE zset:1 0 5
15,474 op/s » LRANGE list 0 99

Concurrency 10
157,582 op/s » PING
132,260 op/s » SET foo bar
143,180 op/s » GET foo
145,747 op/s » INCR number
92,034 op/s » HGETALL hset:1
89,295 op/s » ZRANGE zset:1 0 5
14,229 op/s » LRANGE list 0 99

Concurrency 1
26,111 op/s » PING
24,870 op/s » SET foo bar
25,364 op/s » GET foo
25,348 op/s » INCR number
22,255 op/s » HGETALL hset:1
21,989 op/s » ZRANGE zset:1 0 5
10,139 op/s » LRANGE list 0 99

ioredis npm run bench on same machine for comparison

==========================
redis: 3.2.2
CPU: 8
OS: darwin x64
node version: v8.9.4
current commit: 988d8d9
==========================

SET foo bar
87,895 op/s » javascript parser + dropBufferSupport: true
90,263 op/s » javascript parser

LRANGE foo 0 99
37,174 op/s » javascript parser + dropBufferSupport: true
24,955 op/s » javascript parser

Pipelining

Pipelining works out of the box. The driver works using the async API and the async API defaults to pipelining.

You can still use pipelining to guarantee that all transactions will executed in one request:

Example:

// init pipeline mode
r.rawCall(['multi']);
    r.rawCall(['echo', 'hello world']);
    r.rawCall(['ping']);
    r.rawCall(['incr', 'qqq']);
    r.rawCall(['set', 'foo', 'bar']);
    r.rawCall(['get', 'foo']);
// execute all commands above once
r.rawCall(['exec'], function(e, resp){
    console.log('exec resp', resp);
    // exec resp [ 'hello world', 'PONG', 1, 'OK', 'bar' ]
});

Author

Arseniy Pavlenko h0x91b@gmail.com

Linkedin: https://il.linkedin.com/in/h0x91b

Contributors

Licence

(The MIT License)

Copyright (c) 2015-2018 Arseniy Pavlenko h0x91b@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

changelog

1.2.0 - (2023-06-04)

Announcing Hiredis v1.2.0 with with new adapters, and a great many bug fixes.

🚀 New Features

  • Add sdevent adapter @Oipo (#1144)
  • Allow specifying the keepalive interval @michael-grunder (#1168)
  • Add RedisModule adapter @tezc (#1182)
  • Helper for setting TCP_USER_TIMEOUT socket option @zuiderkwast (#1188)

🐛 Bug Fixes

  • Fix a typo in b6a052f. @yossigo (#1190)
  • Fix wincrypt symbols conflict @hudayou (#1151)
  • Don't attempt to set a timeout if we are in an error state. @michael-grunder (#1180)
  • Accept -nan per the RESP3 spec recommendation. @michael-grunder (#1178)
  • Fix colliding option values @zuiderkwast (#1172)
  • Ensure functionality without _MSC_VER definition @windyakin (#1194)

🧰 Maintenance

  • Add a test for the TCP_USER_TIMEOUT option. @michael-grunder (#1192)
  • Add -Werror as a default. @yossigo (#1193)
  • CI: Update homebrew Redis version. @yossigo (#1191)
  • Fix typo in makefile. @michael-grunder (#1179)
  • Write a version file for the CMake package @Neverlord (#1165)
  • CMakeLists.txt: respect BUILD_SHARED_LIBS @ffontaine (#1147)
  • Cmake static or shared @autoantwort (#1160)
  • fix typo @tillkruss (#1153)
  • Add a test ensuring we don't clobber connection error. @michael-grunder (#1181)
  • Search for openssl on macOS @michael-grunder (#1169)

Contributors

We'd like to thank all the contributors who worked on this release!

1.1.0 - (2022-11-15)

Announcing Hiredis v1.1.0 GA with better SSL convenience, new async adapters and a great many bug fixes.

NOTE: Hiredis can now return nan in addition to -inf and inf when returning a REDIS_REPLY_DOUBLE.

🐛 Bug Fixes

🧰 Maintenance

Contributors

We'd like to thank all the contributors who worked on this release!

1.1.0-rc1 - (2022-11-06)

Announcing Hiredis v1.1.0-rc1, with better SSL convenience, new async adapters, and a great many bug fixes.

🚀 New Features

🐛 Bug Fixes

🧰 Maintenance

Contributors

We'd like to thank all the contributors who worked on this release!

1.0.2 - (2021-10-07)

Announcing Hiredis v1.0.2, which fixes CVE-2021-32765 but returns the SONAME to the correct value of 1.0.0.

1.0.1 - (2021-10-04)

This release erroneously bumped the SONAME, please use 1.0.2

Announcing Hiredis v1.0.1, a security release fixing CVE-2021-32765

Thanks to Yossi Gottlieb for the security fix and to Microsoft Security Vulnerability Research for finding the bug. :sparkling_heart:

1.0.0 - (2020-08-03)

Announcing Hiredis v1.0.0, which adds support for RESP3, SSL connections, allocator injection, and better Windows support! :tada:

A big thanks to everyone who helped with this release. The following list includes everyone who contributed at least five lines, sorted by lines contributed. :sparkling_heart:

Michael Grunder, Yossi Gottlieb, Mark Nunberg, Marcus Geelnard, Justin Brewer, Valentino Geron, Minun Dragonation, Omri Steiner, Sangmoon Yi, Jinjiazh, Odin Hultgren Van Der Horst, Muhammad Zahalqa, Nick Rivera, Qi Yang, kevin1018

Full Changelog

BREAKING CHANGES:

  • redisOptions now has two timeout fields. One for connecting, and one for commands. If you're presently using options->timeout you will need to change it to use options->connect_timeout. (See example)

  • Bulk and multi-bulk lengths less than -1 or greater than LLONG_MAX are now protocol errors. This is consistent with the RESP specification. On 32-bit platforms, the upper bound is lowered to SIZE_MAX.

  • redisReplyObjectFunctions.createArray now takes size_t for its length parameter.

New features:

Closed issues (that involved code changes):

  • Makefile does not install TLS libraries #809
  • redisConnectWithOptions should not set command timeout #722, #829 (valentinogeron)
  • Fix integer overflow in sdsrange #827
  • INFO & CLUSTER commands failed when using RESP3 #802
  • Windows compatibility patches #687, #838, #842
  • RESP3 PUSH messages incorrectly use pending callback #825
  • Asynchronous PSUBSCRIBE command fails when using RESP3 #815
  • New SSL API #804, #813
  • Hard-coded limit of nested reply depth #794
  • Fix TCP_NODELAY in Windows/OSX #679, #690, #779, #785,
  • Added timers to libev adapter. #778, #795
  • Initialization discards const qualifier #777
  • [BUG][MinGW64] Error setting socket timeout #775
  • undefined reference to hi_malloc #769
  • hiredis pkg-config file incorrectly ignores multiarch libdir spec'n #767
  • Don't use -G to build shared object on Solaris #757
  • error when make USE_SSL=1 #748
  • Allow to change SSL Mode #646
  • hiredis/adapters/libevent.h memleak #618
  • redisLibuvPoll crash when server closes the connetion #545
  • about redisAsyncDisconnect question #518
  • hiredis adapters libuv error for help #508
  • API/ABI changes analysis #506
  • Memory leak patch in Redis #502
  • Remove the depth limitation #421

Merged pull requests:

* This Changelog was automatically generated by github_changelog_generator

1.0.0-rc1 - (2020-07-29)

Note: There were no changes to code between v1.0.0-rc1 and v1.0.0 so see v1.0.0 for changelog

0.14.1 (2020-03-13)

  • Adds safe allocation wrappers (CVE-2020-7105, #747, #752) (Michael Grunder)

0.14.0 (2018-09-25)

BREAKING CHANGES:

  • Change redisReply.len to size_t, as it denotes the the size of a string

    User code should compare this to size_t values as well. If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.

  • Make string2ll static to fix conflict with Redis (Tom Lee [c3188b])

  • Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537])
  • Use string2ll from Redis w/added tests (Michael Grunder [7bef04, 60f622])
  • Makefile - OSX compilation fixes (Ryan Schmidt [881fcb, 0e9af8])
  • Remove redundant NULL checks (Justin Brewer [54acc8, 58e6b8])
  • Fix bulk and multi-bulk length truncation (Justin Brewer [109197])
  • Fix SIGSEGV in OpenBSD by checking for NULL before calling freeaddrinfo (Justin Brewer [546d94])
  • Several POSIX compatibility fixes (Justin Brewer [bbeab8, 49bbaa, d1c1b6])
  • Makefile - Compatibility fixes (Dimitri Vorobiev [3238cf, 12a9d1])
  • Makefile - Fix make install on FreeBSD (Zach Shipko [a2ef2b])
  • Makefile - don't assume $(INSTALL) is cp (Igor Gnatenko [725a96])
  • Separate side-effect causing function from assert and small cleanup (amallia [b46413, 3c3234])
  • Don't send negative values to __redisAsyncCommand (Frederik Deweerdt [706129])
  • Fix leak if setsockopt fails (Frederik Deweerdt [e21c9c])
  • Fix libevent leak (zfz [515228])
  • Clean up GCC warning (Ichito Nagata [2ec774])
  • Keep track of errno in __redisSetErrorFromErrno() as snprintf may use it (Jin Qing [25cd88])
  • Solaris compilation fix (Donald Whyte [41b07d])
  • Reorder linker arguments when building examples (Tustfarm-heart [06eedd])
  • Keep track of subscriptions in case of rapid subscribe/unsubscribe (Hyungjin Kim [073dc8, be76c5, d46999])
  • libuv use after free fix (Paul Scott [cbb956])
  • Properly close socket fd on reconnect attempt (WSL [64d1ec])
  • Skip valgrind in OSX tests (Jan-Erik Rediger [9deb78])
  • Various updates for Travis testing OSX (Ted Nyman [fa3774, 16a459, bc0ea5])
  • Update libevent (Chris Xin [386802])
  • Change sds.h for building in C++ projects (Ali Volkan ATLI [f5b32e])
  • Use proper format specifier in redisFormatSdsCommandArgv (Paulino Huerta, Jan-Erik Rediger [360a06, 8655a6])
  • Better handling of NULL reply in example code (Jan-Erik Rediger [1b8ed3])
  • Prevent overflow when formatting an error (Jan-Erik Rediger [0335cb])
  • Compatibility fix for strerror_r (Tom Lee [bb1747])
  • Properly detect integer parse/overflow errors (Justin Brewer [93421f])
  • Adds CI for Windows and cygwin fixes (owent, [6c53d6, 6c3e40])
  • Catch a buffer overflow when formatting the error message
  • Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13
  • Fix warnings, when compiled with -Wshadow
  • Make hiredis compile in Cygwin on Windows, now CI-tested
  • Bulk and multi-bulk lengths less than -1 or greater than LLONG_MAX are now protocol errors. This is consistent with the RESP specification. On 32-bit platforms, the upper bound is lowered to SIZE_MAX.

  • Remove backwards compatibility macro's

This removes the following old function aliases, use the new name now:

Old New
redisReplyReaderCreate redisReaderCreate
redisReplyReaderCreate redisReaderCreate
redisReplyReaderFree redisReaderFree
redisReplyReaderFeed redisReaderFeed
redisReplyReaderGetReply redisReaderGetReply
redisReplyReaderSetPrivdata redisReaderSetPrivdata
redisReplyReaderGetObject redisReaderGetObject
redisReplyReaderGetError redisReaderGetError
  • The DEBUG variable in the Makefile was renamed to DEBUG_FLAGS

Previously it broke some builds for people that had DEBUG set to some arbitrary value, due to debugging other software. By renaming we avoid unintentional name clashes.

Simply rename DEBUG to DEBUG_FLAGS in your environment to make it working again.

0.13.3 (2015-09-16)

  • Revert "Clear REDIS_CONNECTED flag when connection is closed".
  • Make tests pass on FreeBSD (Thanks, Giacomo Olgeni)

If the REDIS_CONNECTED flag is cleared, the async onDisconnect callback function will never be called. This causes problems as the disconnect is never reported back to the user.

0.13.2 (2015-08-25)

  • Prevent crash on pending replies in async code (Thanks, @switch-st)
  • Clear REDIS_CONNECTED flag when connection is closed (Thanks, Jerry Jacobs)
  • Add MacOS X addapter (Thanks, @dizzus)
  • Add Qt adapter (Thanks, Pietro Cerutti)
  • Add Ivykis adapter (Thanks, Gergely Nagy)

All adapters are provided as is and are only tested where possible.

0.13.1 (2015-05-03)

This is a bug fix release. The new reconnect method introduced new struct members, which clashed with pre-defined names in pre-C99 code. Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects. Other non-C99 code can now use hiredis as usual again. Sorry for the inconvenience.

  • Fix memory leak in async reply handling (Salvatore Sanfilippo)
  • Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa)

0.13.0 (2015-04-16)

This release adds a minimal Windows compatibility layer. The parser, standalone since v0.12.0, can now be compiled on Windows (and thus used in other client libraries as well)

  • Windows compatibility layer for parser code (tzickel)
  • Properly escape data printed to PKGCONF file (Dan Skorupski)
  • Fix tests when assert() undefined (Keith Bennett, Matt Stancliff)
  • Implement a reconnect method for the client context, this changes the structure of redisContext (Aaron Bedra)

0.12.1 (2015-01-26)

  • Fix make install: DESTDIR support, install all required files, install PKGCONF in proper location
  • Fix make test as 32 bit build on 64 bit platform

0.12.0 (2015-01-22)

  • Add optional KeepAlive support

  • Try again on EINTR errors

  • Add libuv adapter

  • Add IPv6 support

  • Remove possibility of multiple close on same fd

  • Add ability to bind source address on connect

  • Add redisConnectFd() and redisFreeKeepFd()

  • Fix getaddrinfo() memory leak

  • Free string if it is unused (fixes memory leak)

  • Improve redisAppendCommandArgv performance 2.5x

  • Add support for SO_REUSEADDR

  • Fix redisvFormatCommand format parsing

  • Add GLib 2.0 adapter

  • Refactor reading code into read.c

  • Fix errno error buffers to not clobber errors

  • Generate pkgconf during build

  • Silence BSDSOURCE warnings

  • Improve digit counting for multibulk creation

0.11.0

  • Increase the maximum multi-bulk reply depth to 7.

  • Increase the read buffer size from 2k to 16k.

  • Use poll(2) instead of select(2) to support large fds (>= 1024).

0.10.1

  • Makefile overhaul. Important to check out if you override one or more variables using environment variables or via arguments to the "make" tool.

  • Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements being created by the default reply object functions.

  • Issue #43: Don't crash in an asynchronous context when Redis returns an error reply after the connection has been made (this happens when the maximum number of connections is reached).

0.10.0

  • See commit log.