-
Notifications
You must be signed in to change notification settings - Fork 635
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #870 from codingtwinky/promisify_cache
Promisify cache.js
- Loading branch information
Showing
7 changed files
with
218 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,75 @@ | ||
'use strict'; | ||
const Bluebird = require('bluebird'); | ||
const NodeCache = require('node-cache'); | ||
const cache = Bluebird.promisifyAll(new NodeCache({ stdTTL: 0, errorOnMissing: true })); | ||
const md5 = require('blueimp-md5'); | ||
const funcMap = {}; // Will there ever be a use case where this is a cache with TTL? func registration with TTL? | ||
|
||
const signals = require('signals'); | ||
/** | ||
* @function resolveFunc | ||
* @description Get cached result associated with the key or execute a function to get the result | ||
* @param {string} [key] - A key associated with a function to be executed. | ||
* @return {Promise} - Promise either resolved with cached result of the function or rejected with function not found. | ||
*/ | ||
cache.resolveFunc = (key) => { | ||
return cache.getAsync(key) // Cant do `cache.getAsync(key, true)` due to `get` argument ordering... | ||
.catch({ errorcode: "ENOTFOUND" }, (e) => { | ||
if (!funcMap[key]) throw e; // func associated with key is not found, throw not found error | ||
const result = funcMap[key].func(); // func is found, resolve, set with TTL and return result | ||
return cache.setAsync(key, result, funcMap[key].ttl) | ||
.then(() => { return result }); | ||
}); | ||
} | ||
|
||
// Wraps a function to produce one value at a time no matter how many times invoked, and cache that value until invalidated | ||
module.exports = (constructValue) => { | ||
let constructDone; | ||
let hasCache = false; | ||
/** | ||
* @function registerFunc | ||
* @description Register a function to cache it's result. If same key exists, key is deregistered and registered again. | ||
* @param {ttl} [ttl=0] - ttl in seconds to be used for the cached result of function. | ||
* @param {string} [key=md5 of func] - Key to retrive cached function result. | ||
* @param {function} [func] - Function to be executed to get the result. | ||
* @return {string} - key to retrive cached function result. | ||
*/ | ||
cache.registerFunc = (...args) => { | ||
let func = args.pop(); | ||
let key = args.pop() || md5(func); | ||
let ttl = args.pop() || cache.options.stdTTL; | ||
|
||
let f = (callback) => { | ||
if (hasCache) return callback(f.error, f.value); | ||
if (constructDone) return constructDone.add(callback); | ||
if (typeof func !== "function") { | ||
throw new Error("no function was passed in."); | ||
} | ||
|
||
constructDone = new signals.Signal(); | ||
let localConstructDone = constructDone; | ||
constructDone.add((err, val) => { | ||
constructDone = null; | ||
callback(err, val); | ||
}); | ||
constructValue((err, value) => { | ||
hasCache = true; | ||
f.error = err; | ||
f.value = value; | ||
localConstructDone.dispatch(err, value); | ||
}); | ||
}; | ||
if (isNaN(ttl) || ttl < 0) { | ||
throw new Error("ttl value is not valid."); | ||
} | ||
|
||
if (funcMap[key]) { | ||
cache.deregisterFunc(key); | ||
} | ||
|
||
f.invalidate = () => { | ||
hasCache = false; | ||
f.error = null; | ||
f.value = null; | ||
constructDone = null; | ||
}; | ||
funcMap[key] = { | ||
func: func, | ||
ttl: ttl | ||
} | ||
|
||
return f; | ||
return key; | ||
} | ||
|
||
/** | ||
* @function invalidateFunc | ||
* @description Immediately invalidate cached function result despite ttl value | ||
* @param {string} [key] - A key associated with a function to be executed. | ||
*/ | ||
cache.invalidateFunc = (key) => { | ||
cache.del(key); | ||
} | ||
|
||
/** | ||
* @function deregisterFunc | ||
* @description Remove function registration and invalidate it's cached value. | ||
* @param {string} [key] - A key associated with a function to be executed. | ||
*/ | ||
cache.deregisterFunc = (key) => { | ||
cache.invalidateFunc(key); | ||
delete funcMap[key]; | ||
} | ||
|
||
module.exports = cache; |
Oops, something went wrong.