Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(offlineQueue): add option to limit the offline queue size #241

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Creates a Redis instance
| [options.password] | <code>string</code> | <code>null</code> | If set, client will send AUTH command with the value of this option when connected. |
| [options.enableReadyCheck] | <code>boolean</code> | <code>true</code> | When a connection is established to the Redis server, the server might still be loading the database from disk. While loading, the server not respond to any commands. To work around this, when this option is `true`, ioredis will check the status of the Redis server, and when the Redis server is able to process commands, a `ready` event will be emitted. |
| [options.enableOfflineQueue] | <code>boolean</code> | <code>true</code> | By default, if there is no active connection to the Redis server, commands are added to a queue and are executed once the connection is "ready" (when `enableReadyCheck` is `true`, "ready" means the Redis server has loaded the database from disk, otherwise means the connection to the Redis server has been established). If this option is false, when execute the command when the connection isn't ready, an error will be returned. |
| [options.maxOfflineQueueSize] | <code>number</code> | <code>Infinity</code> | The max size of offline queue. when the max size is reached, the oldest command will be shifted out from the offline queue and rejected with an error of "Offline queue is full". |
| [options.connectTimeout] | <code>number</code> | <code>10000</code> | The milliseconds before a timeout occurs during the initial connection to the Redis server. |
| [options.autoResubscribe] | <code>boolean</code> | <code>true</code> | After reconnected, if the previous connection was in the subscriber mode, client will auto re-subscribe these channels. |
| [options.autoResendUnfulfilledCommands] | <code>boolean</code> | <code>true</code> | If true, client will resend unfulfilled commands(e.g. block commands) in the previous connection when reconnected. |
Expand Down
8 changes: 8 additions & 0 deletions lib/redis.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ try {
* "ready" means the Redis server has loaded the database from disk, otherwise means the connection
* to the Redis server has been established). If this option is false,
* when execute the command when the connection isn't ready, an error will be returned.
* @param {number} [options.maxOfflineQueueSize=Infinity] - The max size of offline queue.
* when the max size is reached, the oldest command will be shifted out from the offline queue
* and rejected with an error of "Offline queue is full".
* @param {number} [options.connectTimeout=10000] - The milliseconds before a timeout occurs during the initial
* connection to the Redis server.
* @param {boolean} [options.autoResubscribe=true] - After reconnected, if the previous connection was in the
Expand Down Expand Up @@ -173,6 +176,7 @@ Redis.defaultOptions = {
parser: 'auto',
enableOfflineQueue: true,
enableReadyCheck: true,
maxOfflineQueueSize: Infinity,
autoResubscribe: true,
autoResendUnfulfilledCommands: true,
lazyConnect: false,
Expand Down Expand Up @@ -532,6 +536,10 @@ Redis.prototype.sendCommand = function (command, stream) {
}
} else if (this.options.enableOfflineQueue) {
debug('queue command[%d] -> %s(%s)', this.condition.select, command.name, command.args);
if (this.offlineQueue.length >= this.options.maxOfflineQueueSize) {
var item = this.offlineQueue.shift();
item.command.reject(new Error('Offline queue is full'));
}
this.offlineQueue.push({
command: command,
stream: stream,
Expand Down
31 changes: 31 additions & 0 deletions test/functional/offline_queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

describe('offline queue', function () {
context('maxOfflineQueueSize', function () {
it('should shift out the oldest command', function (done) {
var redis = new Redis({
maxOfflineQueueSize: 3,
port: 17891
});

var rejected = 0;
redis.set('foo', 'bar', function (err) {
expect(++rejected).to.eql(1);
expect(err).to.have.property('message', 'Offline queue is full');
});

redis.set('foo', 'bar', function (err) {
expect(++rejected).to.eql(2);
expect(err).to.have.property('message', 'Offline queue is full');
expect(redis.offlineQueue.get(0).command.args[0]).to.eql('foo1');
expect(redis.offlineQueue.get(1).command.args[0]).to.eql('foo2');
expect(redis.offlineQueue.get(2).command.args[0]).to.eql('foo3');
done();
});

redis.set('foo1', 'bar');
redis.set('foo2', 'bar');
redis.set('foo3', 'bar');
});
});
});