Last active
April 14, 2017 21:00
-
-
Save dhigginbotham/c69266cbc47e865aad435766985e0777 to your computer and use it in GitHub Desktop.
Volatile cache
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
const log = require('debug')('bot:app:shared:cacheable:'); | |
const ms = require('ms'); | |
/** | |
* Volatile state/cache machine | |
* @param { object } settings - Settings for cache, includes | |
*/ | |
function cacheable(settings = {}) { | |
const { key = 'cacheable', ttl = '3h', staleMaths = 0.65 } = settings; | |
if (!(settings.hasOwnProperty('expires'))) settings.expires = 0; | |
/** | |
* flush the cache, resets back to an empty object or array, depending | |
* on how you interact with it | |
*/ | |
function flush() { | |
settings.cache = Array.isArray(settings.cache) ? [] : {}; | |
return true; | |
} | |
/** | |
* determine cache size either by `Object.keys` or `Array.length` | |
* @return { number } | |
*/ | |
function size() { | |
if (!(settings.hasOwnProperty('cache'))) flush(); | |
return Array.isArray(settings.cache) | |
? settings.cache.length | |
: Object.keys(settings.cache).length; | |
} | |
/** | |
* reset's stale/ttl from ts provided with additional offset | |
* @param now - Defaults to `Date.now()`, however you can provide | |
* an future date, or a past date to do some funky stuff | |
*/ | |
function reset(ts = Date.now()) { | |
settings.ts = ts; | |
settings.expires = settings.ts + ms(ttl); | |
settings.stale = settings.ts + (ms(ttl) * staleMaths); | |
return true; | |
} | |
/** | |
* determine if cache state is expired | |
* @return { boolean } - value if cache is expired or not | |
*/ | |
function expired() { | |
const now = Date.now(); | |
let isExpired = false; | |
const cacheSize = size(); | |
if (now >= settings.expires || !cacheSize) isExpired = true; | |
return isExpired; | |
} | |
/** | |
* determine if the cache state is stale | |
* @return { boolean } - value if cache is stale or not | |
* @param now { number } - defaults to now, but i can | |
* see maybe wanting to have control over that adhoc | |
*/ | |
function stale(now = Date.now()) { | |
return !expired() && now >= settings.stale; | |
} | |
/** | |
* determines full cache state, if expired, we'll clean up | |
* @return { boolean } - whether cache is expired or not | |
*/ | |
function state() { | |
const now = Date.now(); | |
const isExpired = expired(); | |
const cacheSize = size(); | |
const isStale = stale(); | |
if (isExpired && cacheSize) flush(); | |
if (isExpired) reset(); | |
log('%s:isExpired:%s:cacheSize:%d:isStale:%s:expiresInSecs:%d:staleInSecs:%d', | |
key, isExpired, cacheSize, isStale, | |
`${Math.round((settings.expires - now) / 1000)}`, | |
`${Math.round((settings.stale - now) / 1000)}`); | |
return isExpired; | |
} | |
return { expired, flush, size, stale, state, reset }; | |
} | |
module.exports = { cacheable }; |
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
const store = { | |
key: 'expensiveCacheExample', | |
cache: {}, | |
ttl: '1h' | |
}; | |
const expired = cacheable(store).state; // pulls state out to manage state and check if expired | |
const { stale, reset, flush } = cacheable(store); // other helpful tings | |
// example usage for expensive or long running functions | |
function doSomethingExpensive(fn) { | |
const isStale = stale(); | |
if (!expired() && !isStale) return fn(null, store.cache); | |
if (isStale) fn(null, store.cache); | |
return funcToExpensiveThings((err, resp) => { | |
if (err) return fn(new Error(err), null); | |
store.cache = resp; | |
if (isStale) return reset(); | |
return fn(null, resp); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment