From b12c49a20785d9b608158655e79638fac5d2fa2e Mon Sep 17 00:00:00 2001 From: Bryce Baril Date: Wed, 2 Oct 2013 16:10:26 -0700 Subject: [PATCH] Add unref() method to RedisClient that will call unref() on the socket connection, allowing it to close when unused. This is experimental because it does not yet understand the Redis protocol, so subscriptions or blocking operations will not work correctly. --- README.md | 20 ++++++++++++++++++++ index.js | 14 ++++++++++++++ test-unref.js | 12 ++++++++++++ test.js | 18 ++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 test-unref.js diff --git a/README.md b/README.md index b9285af50e..babf5bf4be 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,26 @@ want to do this: `client.end()` is useful for timeout cases where something is stuck or taking too long and you want to start over. +## client.unref() + +Call `unref()` on the underlying socket connection to the Redis server, allowing the program to exit once no more commands are pending. + +This is an **experimental** feature, and only supports a subset of the Redis protocol. Any commands where client state is saved on the Redis server, e.g. `*SUBSCRIBE` or the blocking `BL*` commands will *NOT* work with `.unref()`. + +```js +var redis = require("redis") +var client = redis.createClient() + +/* + Calling unref() will allow this program to exit immediately after the get command finishes. Otherwise the client would hang as long as the client-server connection is alive. +*/ +client.unref() +client.get("foo", function (err, value){ + if (err) throw(err) + console.log(value) +}) +``` + ## Friendlier hash commands Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings. diff --git a/index.js b/index.js index 38606be769..7a93a58dc8 100644 --- a/index.js +++ b/index.js @@ -121,6 +121,20 @@ RedisClient.prototype.initialize_retry_vars = function () { this.attempts = 1; }; +RedisClient.prototype.unref = function () { + trace("User requesting to unref the connection"); + if (this.connected) { + trace("unref'ing the socket connection"); + this.stream.unref(); + } + else { + trace("Not connected yet, will unref later"); + this.once("connect", function () { + this.unref(); + }) + } +}; + // flush offline_queue and command_queue, erroring any items with a callback first RedisClient.prototype.flush_and_error = function (message) { var command_obj; diff --git a/test-unref.js b/test-unref.js new file mode 100644 index 0000000000..4a3cc3622d --- /dev/null +++ b/test-unref.js @@ -0,0 +1,12 @@ +var redis = require("./") +//redis.debug_mode = true +var PORT = process.argv[2] || 6379; +var HOST = process.argv[3] || '127.0.0.1'; + +var c = redis.createClient(PORT, HOST) +c.unref() +c.info(function (err, reply) { + if (err) process.exit(-1) + if (!reply.length) process.exit(-1) + process.stdout.write(reply.length.toString()) +}) \ No newline at end of file diff --git a/test.js b/test.js index 5e204bc2c7..89f67e1b34 100644 --- a/test.js +++ b/test.js @@ -10,6 +10,7 @@ var redis = require("./index"), assert = require("assert"), crypto = require("crypto"), util = require("./lib/util"), + fork = require("child_process").fork, test_db_num = 15, // this DB will be flushed and used for testing tests = {}, connected = false, @@ -2013,6 +2014,23 @@ tests.reconnectRetryMaxDelay = function() { }); }; +tests.unref = function () { + var name = "unref"; + var external = fork("./test-unref.js"); + var done = false; + external.on("close", function (code) { + assert(code == 0, "test-unref.js failed"); + done = true; + }) + setTimeout(function () { + if (!done) { + external.kill(); + } + assert(done, "test-unref.js didn't finish in time."); + next(name); + }, 100); +}; + all_tests = Object.keys(tests); all_start = new Date(); test_count = 0;