Skip to content

Commit bd87ac7

Browse files
author
Kevin Whitley
committed
expiration callback works... added globalOptions.events object for callbacks
1 parent a662070 commit bd87ac7

File tree

4 files changed

+88
-56
lines changed

4 files changed

+88
-56
lines changed

src/apicache.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ function ApiCache() {
4141
include: [],
4242
exclude: [],
4343
},
44+
events: {
45+
'expire': undefined
46+
},
4447
headers: {
4548
// 'cache-control': 'no-cache' // example of header overwrite
4649
}
@@ -95,16 +98,18 @@ function ApiCache() {
9598

9699
function cacheResponse(key, value, duration) {
97100
var redis = globalOptions.redisClient
101+
var expireCallback = globalOptions.events.expire
102+
98103
if (redis) {
99104
try {
100105
redis.hset(key, "response", JSON.stringify(value))
101106
redis.hset(key, "duration", duration)
102-
redis.expire(key, duration/1000)
107+
redis.expire(key, duration/1000, expireCallback)
103108
} catch (err) {
104-
console.log('[apicache] error in redis.hset()')
109+
debug('[apicache] error in redis.hset()')
105110
}
106111
} else {
107-
memCache.add(key, value, duration)
112+
memCache.add(key, value, duration, expireCallback)
108113
}
109114

110115
// add automatic cache clearing from duration, includes max limit on setTimeout
@@ -348,7 +353,12 @@ function ApiCache() {
348353
}
349354

350355
if (opt.appendKey.length > 0) {
351-
key += '$$appendKey=' + opt.appendKey.map(function(attr) { return req[attr] }).join('+')
356+
var appendKey = req
357+
358+
for (var i = 0; i < opt.appendKey.length; i++) {
359+
appendKey = appendKey[opt.appendKey[i]]
360+
}
361+
key += '$$appendKey=' + appendKey
352362
}
353363

354364
// attempt cache hit

src/memory-cache.js

+33-41
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,59 @@
11
function MemoryCache() {
2-
this.cache = {}
3-
this.size = 0
2+
this.cache = {}
3+
this.size = 0
44
}
55

66
MemoryCache.prototype.add = function(key, value, time, timeoutCallback) {
7-
var old = this.cache[key]
8-
var instance = this
9-
10-
if (old) {
11-
clearTimeout(old.timeout)
12-
}
13-
14-
var entry = {
15-
value: value,
16-
expire: time + Date.now(),
17-
timeout: setTimeout(function() {
18-
instance.delete(key)
19-
return timeoutCallback && typeof timeoutCallback === 'function' && timeoutCallback(value, key)
20-
}, time)
21-
}
22-
23-
this.cache[key] = entry
24-
this.size = Object.keys(this.cache).length
25-
26-
return entry
7+
var old = this.cache[key]
8+
var instance = this
9+
10+
var entry = {
11+
value: value,
12+
expire: time + Date.now(),
13+
timeout: setTimeout(function() {
14+
instance.delete(key)
15+
return timeoutCallback && typeof timeoutCallback === 'function' && timeoutCallback(value, key)
16+
}, time)
17+
}
18+
19+
this.cache[key] = entry
20+
this.size = Object.keys(this.cache).length
21+
22+
return entry
2723
}
2824

2925
MemoryCache.prototype.delete = function(key) {
30-
var entry = this.cache[key]
26+
var entry = this.cache[key]
3127

32-
if (entry) {
33-
clearTimeout(entry.timeout)
34-
}
28+
if (entry) {
29+
clearTimeout(entry.timeout)
30+
}
3531

36-
delete this.cache[key]
32+
delete this.cache[key]
3733

38-
this.size = Object.keys(this.cache).length
34+
this.size = Object.keys(this.cache).length
3935

40-
return null
36+
return null
4137
}
4238

4339
MemoryCache.prototype.get = function(key) {
44-
var entry = this.cache[key]
40+
var entry = this.cache[key]
4541

46-
if (entry && entry.expire < Date.now()) {
47-
return this.delete(key)
48-
}
49-
50-
return entry
42+
return entry
5143
}
5244

5345
MemoryCache.prototype.getValue = function(key) {
54-
var entry = this.get(key)
46+
var entry = this.get(key)
5547

56-
return entry && entry.value
48+
return entry && entry.value
5749
}
5850

5951
MemoryCache.prototype.clear = function() {
60-
Object.keys(this.cache).forEach(function(key) {
61-
this.delete(key)
62-
}, this)
52+
Object.keys(this.cache).forEach(function(key) {
53+
this.delete(key)
54+
}, this)
6355

64-
return true
56+
return true
6557
}
6658

6759
module.exports = MemoryCache

test/api/lib/routes.js

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ module.exports = function(app) {
99
res.json(movies)
1010
})
1111

12+
app.get('/api/params/:where', function(req, res) {
13+
app.requestsProcessed++
14+
15+
res.json(movies)
16+
})
17+
18+
1219
app.get('/api/writeandend', function(req, res) {
1320
app.requestsProcessed++
1421

test/apicache_test.js

+34-11
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ describe('.middleware {MIDDLEWARE}', function() {
161161
jsonp: false,
162162
redisClient: false,
163163
statusCodes: { include: [], exclude: [] },
164+
events: { expire: undefined },
164165
headers: {}
165166
})
166167
expect(middleware2.options()).to.eql({
@@ -171,6 +172,7 @@ describe('.middleware {MIDDLEWARE}', function() {
171172
jsonp: false,
172173
redisClient: false,
173174
statusCodes: { include: [], exclude: [] },
175+
events: { expire: undefined },
174176
headers: {}
175177
})
176178
})
@@ -184,6 +186,7 @@ describe('.middleware {MIDDLEWARE}', function() {
184186
defaultDuration: 7200000,
185187
appendKey: ['bar'],
186188
statusCodes: { include: [], exclude: ['400'] },
189+
events: { expire: undefined },
187190
headers: {
188191
'cache-control': 'no-cache'
189192
}
@@ -192,7 +195,8 @@ describe('.middleware {MIDDLEWARE}', function() {
192195
debug: false,
193196
defaultDuration: 1800000,
194197
appendKey: ['foo'],
195-
statusCodes: { include: [], exclude: ['200'] }
198+
statusCodes: { include: [], exclude: ['200'] },
199+
events: { expire: undefined },
196200
})
197201
expect(middleware1.options()).to.eql({
198202
debug: true,
@@ -202,6 +206,7 @@ describe('.middleware {MIDDLEWARE}', function() {
202206
jsonp: false,
203207
redisClient: false,
204208
statusCodes: { include: [], exclude: ['400'] },
209+
events: { expire: undefined },
205210
headers: {
206211
'cache-control': 'no-cache'
207212
}
@@ -214,6 +219,7 @@ describe('.middleware {MIDDLEWARE}', function() {
214219
jsonp: false,
215220
redisClient: false,
216221
statusCodes: { include: [], exclude: ['200'] },
222+
events: { expire: undefined },
217223
headers: {}
218224
})
219225
})
@@ -243,6 +249,7 @@ describe('.middleware {MIDDLEWARE}', function() {
243249
jsonp: false,
244250
redisClient: false,
245251
statusCodes: { include: [], exclude: ['400'] },
252+
events: { expire: undefined },
246253
headers: {}
247254
})
248255
expect(middleware2.options()).to.eql({
@@ -253,6 +260,7 @@ describe('.middleware {MIDDLEWARE}', function() {
253260
jsonp: false,
254261
redisClient: false,
255262
statusCodes: { include: [], exclude: ['200'] },
263+
events: { expire: undefined },
256264
headers: {}
257265
})
258266
})
@@ -291,6 +299,7 @@ describe('.middleware {MIDDLEWARE}', function() {
291299
jsonp: false,
292300
redisClient: false,
293301
statusCodes: { include: [], exclude: [] },
302+
events: { expire: undefined },
294303
headers: {
295304
'cache-control': 'no-cache'
296305
}
@@ -303,6 +312,7 @@ describe('.middleware {MIDDLEWARE}', function() {
303312
jsonp: false,
304313
redisClient: false,
305314
statusCodes: { include: [], exclude: [] },
315+
events: { expire: undefined },
306316
headers: {}
307317
})
308318
})
@@ -392,22 +402,15 @@ describe('.middleware {MIDDLEWARE}', function() {
392402
})
393403

394404
it('properly uses appendKey params', function() {
395-
var app = mockAPI.create('10 seconds', { appendKey: ['method', 'url'] })
405+
var app = mockAPI.create('10 seconds', { appendKey: ['method'] })
396406

397407
return request(app)
398408
.get('/api/movies')
399409
.expect(200, movies)
400410
.then(assertNumRequestsProcessed(app, 1))
401411
.then(function() {
402-
return request(app)
403-
.get('/api/movies')
404-
.set('Accept', 'application/json')
405-
.expect('Content-Type', /json/)
406-
.expect(200, movies)
407-
.then(function(res) {
408-
expect(app.apicache.getIndex().all.length).to.equal(1)
409-
expect(app.apicache.getIndex().all[0]).to.equal('/api/movies$$appendKey=GET+/api/movies')
410-
})
412+
expect(app.apicache.getIndex().all.length).to.equal(1)
413+
expect(app.apicache.getIndex().all[0]).to.equal('/api/movies$$appendKey=GET')
411414
})
412415
})
413416

@@ -583,6 +586,26 @@ describe('.middleware {MIDDLEWARE}', function() {
583586
}, 25)
584587
})
585588

589+
it('executes expiration callback from globalOptions.events.expire upon entry expiration', function(done) {
590+
var callbackResponse = undefined
591+
var cb = function(a,b) {
592+
callbackResponse = b
593+
}
594+
var app = mockAPI.create(10, { events: { expire: cb }})
595+
596+
request(app)
597+
.get('/api/movies')
598+
.end(function(err, res) {
599+
expect(app.apicache.getIndex().all.length).to.equal(1)
600+
expect(app.apicache.getIndex().all).to.include('/api/movies')
601+
})
602+
603+
setTimeout(function() {
604+
expect(app.apicache.getIndex().all).to.have.length(0)
605+
expect(callbackResponse).to.equal('/api/movies')
606+
done()
607+
}, 25)
608+
})
586609
})
587610
})
588611
})

0 commit comments

Comments
 (0)