Skip to content

Commit

Permalink
feat: True timeouts for cache calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Krems committed Jan 26, 2016
1 parent bbe1b76 commit 5f94b5f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
12 changes: 10 additions & 2 deletions lib/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Cache.prototype._set = function _set(key, val, options) {
}, options);
}

return util.toPromise(val).then(writeToBackend);
return this._applyTimeout(util.toPromise(val).then(writeToBackend));
};

Cache.prototype.set = function set(rawKey, val, _opts, _cb) {
Expand All @@ -98,8 +98,16 @@ Cache.prototype.set = function set(rawKey, val, _opts, _cb) {
return this._set(key, val, optsWithDefaults).nodeify(args.cb);
};

Cache.prototype._applyTimeout = function _applyTimeout(value) {
var timeoutMs = this.defaults.timeout;
if (timeoutMs > 0) {
return value.timeout(timeoutMs);
}
return value;
};

Cache.prototype._getWrapped = function _getWrapped(key) {
return this.backend.get(key);
return this._applyTimeout(this.backend.get(key));
};
// For backwards compatibility, eventually we should deprecate this.
// It *should* be a private API.
Expand Down
80 changes: 80 additions & 0 deletions test/timeout.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import assert from 'assertive';
import Bluebird from 'bluebird';
import { identity } from 'lodash';

import Cache from '../lib/cache';

describe('Cache timeouts', () => {
const cache = new Cache({
backend: {
get() {
return Bluebird.resolve({ d: 'get result' }).delay(150);
},
set() {
return Bluebird.resolve('set result').delay(150);
},
},
name: 'awesome-name',
debug: true,
});

describe('with a timeout <150ms', () => {
before(() => cache.defaults.timeout = 50);

it('get fails fast', async () => {
const err = await Bluebird.race([
cache.get('my-key').then(null, identity),
Bluebird.delay(100, 'too slow'), // this should not be used
]);
assert.expect(err instanceof Error);
assert.equal('TimeoutError', err.name);
});

it('set fails fast', async () => {
const err = await Bluebird.race([
cache.set('my-key', 'my-value').then(null, identity),
Bluebird.delay(100, 'too slow'), // this should not be used
]);
assert.expect(err instanceof Error);
assert.equal('TimeoutError', err.name);
});

it('getOrElse fails fast', async () => {
const value = await Bluebird.race([
cache.getOrElse('my-key', 'my-value').then(null, identity),
// We need to add a bit of time here because we'll run into the
// timeout twice - once when trying to read and once while writing.
Bluebird.delay(150, 'too slow'), // this should not be used
]);
assert.equal('my-value', value);
});
});

describe('with a timeout >150ms', () => {
before(() => cache.defaults.timeout = 250);

it('receives the value', async () => {
const value = await Bluebird.race([
cache.get('my-key').then(null, identity),
Bluebird.delay(200, 'too slow'), // this should not be used
]);
assert.equal('get result', value);
});

it('sets the value', async () => {
const value = await Bluebird.race([
cache.set('my-key', 'my-value').then(null, identity),
Bluebird.delay(200, 'too slow'), // this should not be used
]);
assert.equal('set result', value);
});

it('getOrElse can retrieve a value', async () => {
const value = await Bluebird.race([
cache.getOrElse('my-key', 'my-value').then(null, identity),
Bluebird.delay(200, 'too slow'), // this should not be used
]);
assert.equal('get result', value);
});
});
});

0 comments on commit 5f94b5f

Please sign in to comment.