-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
executable file
·125 lines (97 loc) · 2.31 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
'use strict'
const sigmund = require('sigmund')
const { isNil } = require('lodash')
const redis = require('./redis')
const lru = require('./lru')
const keygen = (name, args) => {
const input = { f: name, a: args }
return sigmund(input, 8)
}
let anonFnId = 0
class Memoise {
/**
*
* Constructor
*
* Creates a new cache instance with redis if env vars are set or lru
*
* @param {Object} Cache Options
* ```js
* {
* maxAge: Number // cache age
* max: Number // max number of item which can fit
* }
* ```
*
**/
constructor (options = {}) {
let store = redis.init(options)
if (isNil(store)) {
console.log('(memoise) redis store not initialised. falling back to lru')
store = lru.init(options)
}
if (isNil(store)) {
throw new Error('(memoise) No store initialised')
}
this.store = store
this.fname = ''
this.stats = { hit: 0, miss: 0, error: 0 }
}
/**
*
* ## wrap
*
* @param {Function} function to be wrapped
* @return {Function} Wrapped function that is cache aware
*
* Given a function, generates a cache aware version of it.
* The given function must be an async function
*
**/
wrap (fn) {
const stats = this.stats
const fname = `${__filename}_${fn.name || anonFnId++}`
this.fname = fname
const cachedFunc = async (...args) => {
const key = keygen(fname, args)
let data
try {
data = await this.store.get(key)
} catch (error) {
console.error(error)
stats.error++
}
if (!isNil(data)) {
stats.hit++
return data
}
stats.miss++
const reserved = await this.store.reserve(key)
let result
if (reserved) {
result = await fn(...args)
if (isNil(result)) {
return result
}
try {
await this.store.set(key, result)
} catch (error) {
console.error(error)
stats.error++
}
} else {
result = await this.store.listen(key)
}
return result
}
return cachedFunc
}
invalidate (...args) {
const key = keygen(this.fname, args)
return this.store.expire(key)
}
debug () {
return { fname: this.fname, stats: this.stats }
}
}
module.exports = Memoise