From a5e89ac86661bfcc888faca044d376fbf4ed74c8 Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Sun, 28 Aug 2016 12:19:23 -0400 Subject: [PATCH 1/6] make sure to expire the same key that was added --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index aa7c33e..9839a82 100644 --- a/index.js +++ b/index.js @@ -65,7 +65,7 @@ class RedisCache { this.client.multi() .set(key, body) - .expire(path, this.expiration) + .expire(key, this.expiration) .exec(err => { if (err) { rej(err); From b412b59ce541852dcd5837523a8f34cbb6d7c1a6 Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Wed, 1 Feb 2017 20:49:05 -0500 Subject: [PATCH 2/6] added cache key index for getting cache key by path --- index.js | 1 + test/caching-test.js | 1 + 2 files changed, 2 insertions(+) diff --git a/index.js b/index.js index 9839a82..4040728 100644 --- a/index.js +++ b/index.js @@ -65,6 +65,7 @@ class RedisCache { this.client.multi() .set(key, body) + .set(`key_index_${path}`, key) .expire(key, this.expiration) .exec(err => { if (err) { diff --git a/test/caching-test.js b/test/caching-test.js index a54e8d8..5bee7b0 100644 --- a/test/caching-test.js +++ b/test/caching-test.js @@ -86,6 +86,7 @@ describe('caching tests', function() { return cache.put('/', body, mockResponse).then(() => { expect(mockRedis['/_mmmmmm']).to.equal(body); + expect(mockRedis['key_index_/']).to.equal('/_mmmmmm'); }); }); From 34b0eec569d6374476f0d31b618eea9306269f22 Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Fri, 3 Feb 2017 16:40:14 -0500 Subject: [PATCH 3/6] added document ID cache key index option --- index.js | 4 +++- test/caching-test.js | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 4040728..3f0c3d9 100644 --- a/index.js +++ b/index.js @@ -52,6 +52,8 @@ class RedisCache { let request = response && response.req; let key = this.cacheKey(path, request); + let documentIdMatch = /\/([\d]+)/.exec(path); + let documentId = documentIdMatch && documentIdMatch.length ? documentIdMatch[1] : null; return new Promise((res, rej) => { let statusCode = response && response.statusCode; @@ -65,7 +67,7 @@ class RedisCache { this.client.multi() .set(key, body) - .set(`key_index_${path}`, key) + .set(`key_index_${documentId || path}`, key) .expire(key, this.expiration) .exec(err => { if (err) { diff --git a/test/caching-test.js b/test/caching-test.js index 5bee7b0..badf14f 100644 --- a/test/caching-test.js +++ b/test/caching-test.js @@ -90,6 +90,22 @@ describe('caching tests', function() { }); }); + it('can build a custom cache key from the documentId prefix', function() { + let body = 'Hola'; + let mockResponse = { + req: { + cookies: { + chocolateChip: 'mmmmmm' + } + } + }; + + return cache.put('/123-abc', body, mockResponse).then(() => { + expect(mockRedis['/123-abc_mmmmmm']).to.equal(body); + expect(mockRedis.key_index_123).to.equal('/123-abc_mmmmmm'); + }); + }); + it('can get a cache item based on a custom cache key', function() { let body = 'Hola'; let cookieValue = 'mmmmmm'; From 5ee7f8217f817d74ad3301791a004a56f8c4f17c Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Sun, 12 Feb 2017 12:37:43 -0500 Subject: [PATCH 4/6] updated to allow cache key index to support mulitple values --- index.js | 42 +++++++++++++++++++------ test/caching-test.js | 73 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 15 deletions(-) diff --git a/index.js b/index.js index 3f0c3d9..97dc286 100644 --- a/index.js +++ b/index.js @@ -58,6 +58,7 @@ class RedisCache { return new Promise((res, rej) => { let statusCode = response && response.statusCode; let statusCodeStr = statusCode && (statusCode + ''); + let keyIndex = `key_index_${documentId || path}`; if (statusCodeStr && statusCodeStr.length && (statusCodeStr.charAt(0) === '4' || statusCodeStr.charAt(0) === '5')) { @@ -65,17 +66,40 @@ class RedisCache { return; } - this.client.multi() - .set(key, body) - .set(`key_index_${documentId || path}`, key) - .expire(key, this.expiration) - .exec(err => { - if (err) { - rej(err); + this.client.get(keyIndex, (err, reply) => { + if (err) { + rej(err); + } else { + let keys; + if (!reply) { + keys = []; } else { - res(); + try { + keys = JSON.parse(reply); + } catch (e) { + console.error(`can't parse key index for ${keyIndex}: ${reply}`); + keys = [ reply ]; + } } - }); + + keys.push(key); + + console.log(`Creating cache key ${key}`); + console.log(`Setting cache key-index ${keyIndex}: ${JSON.stringify(keys)}`); + + this.client.multi() + .set(key, body) + .set(keyIndex, JSON.stringify(keys)) + .expire(key, this.expiration) + .exec(err => { + if (err) { + rej(err); + } else { + res(); + } + }); + } + }); }); } } diff --git a/test/caching-test.js b/test/caching-test.js index badf14f..c5240c6 100644 --- a/test/caching-test.js +++ b/test/caching-test.js @@ -66,7 +66,7 @@ describe('caching tests', function() { beforeEach(function() { cache = new RedisCache({ cacheKey (path, request) { - return `${path}_${request && request.cookies && request.cookies.chocolateChip}`; + return `${request.hostname}${path}_${request && request.cookies && request.cookies.chocolateChip}`; } }); cache.client = mockRedisClient(); @@ -78,6 +78,7 @@ describe('caching tests', function() { let body = 'Hola'; let mockResponse = { req: { + hostname: 'foo.com', cookies: { chocolateChip: 'mmmmmm' } @@ -85,8 +86,66 @@ describe('caching tests', function() { }; return cache.put('/', body, mockResponse).then(() => { - expect(mockRedis['/_mmmmmm']).to.equal(body); - expect(mockRedis['key_index_/']).to.equal('/_mmmmmm'); + expect(mockRedis['foo.com/_mmmmmm']).to.equal(body); + expect(mockRedis['key_index_/']).to.equal(JSON.stringify(['foo.com/_mmmmmm'])); + }); + }); + + it('can represent mulitple cache keys from different domains with the same path', function() { + let body = 'Hola'; + let body2 = 'Bonjour'; + let mockResponse = { + req: { + hostname: 'foo.com', + cookies: { + chocolateChip: 'mmmmmm' + } + } + }; + let mockResponse2 = { + req: { + hostname: 'bar.com', + cookies: { + chocolateChip: 'mmmmmm' + } + } + }; + + return cache.put('/', body, mockResponse) + .then(() => { + expect(mockRedis['foo.com/_mmmmmm']).to.equal(body); + expect(mockRedis['key_index_/']).to.equal(JSON.stringify(['foo.com/_mmmmmm'])); + }) + .then(() => cache.put('/', body2, mockResponse2)) + .then(() => { + expect(mockRedis['foo.com/_mmmmmm']).to.equal(body); + expect(mockRedis['bar.com/_mmmmmm']).to.equal(body2); + expect(mockRedis['key_index_/']).to.equal(JSON.stringify([ + 'foo.com/_mmmmmm', + 'bar.com/_mmmmmm' + ])); + }); + }); + + it('can handle non-JSON keys (migration test)', function() { + mockRedis[`key_index_/`] = 'garbage_key'; + let body = 'Hola'; + let mockResponse = { + req: { + hostname: 'foo.com', + cookies: { + chocolateChip: 'mmmmmm' + } + } + }; + + return cache.put('/', body, mockResponse) + .then(() => { + expect(mockRedis['foo.com/_mmmmmm']).to.equal(body); + expect(mockRedis['key_index_/']).to.equal(JSON.stringify([ + 'garbage_key', + 'foo.com/_mmmmmm' + ])); }); }); @@ -94,6 +153,7 @@ describe('caching tests', function() { let body = 'Hola'; let mockResponse = { req: { + hostname: 'foo.com', cookies: { chocolateChip: 'mmmmmm' } @@ -101,16 +161,17 @@ describe('caching tests', function() { }; return cache.put('/123-abc', body, mockResponse).then(() => { - expect(mockRedis['/123-abc_mmmmmm']).to.equal(body); - expect(mockRedis.key_index_123).to.equal('/123-abc_mmmmmm'); + expect(mockRedis['foo.com/123-abc_mmmmmm']).to.equal(body); + expect(mockRedis.key_index_123).to.equal(JSON.stringify(['foo.com/123-abc_mmmmmm'])); }); }); it('can get a cache item based on a custom cache key', function() { let body = 'Hola'; let cookieValue = 'mmmmmm'; - mockRedis[`/_${cookieValue}`] = body; + mockRedis[`foo.com/_${cookieValue}`] = body; let mockRequest = { + hostname: 'foo.com', cookies: { chocolateChip: cookieValue } From 32fae7268e3d6de2c667f839a96f395d06cb1a7e Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Fri, 24 Mar 2017 20:50:54 -0400 Subject: [PATCH 5/6] bump version to make yarn happy --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b28af91..eb02fcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fastboot-redis-cache", - "version": "0.1.0", + "version": "0.1.1", "description": "A FastBoot App Server cache for Redis", "main": "index.js", "scripts": { From 607cfbf8e64a7326423719bd6d41ac150991bca9 Mon Sep 17 00:00:00 2001 From: Hassan Abdel-Rahman Date: Sat, 29 Apr 2017 10:47:28 -0400 Subject: [PATCH 6/6] set expiration for key index nodes --- index.js | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 97dc286..d6a4be5 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ const redis = require('redis'); const FIVE_MINUTES = 5 * 60; +const ONE_HOUR = 12 * FIVE_MINUTES; class RedisCache { constructor(options) { @@ -91,6 +92,7 @@ class RedisCache { .set(key, body) .set(keyIndex, JSON.stringify(keys)) .expire(key, this.expiration) + .expire(keyIndex, ONE_HOUR) .exec(err => { if (err) { rej(err); diff --git a/package.json b/package.json index eb02fcf..6be1884 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fastboot-redis-cache", - "version": "0.1.1", + "version": "0.1.2", "description": "A FastBoot App Server cache for Redis", "main": "index.js", "scripts": {