lru-cache-for-clusters-as-promised
LRU Cache for Clusters as Promised provides a cluster-safe lru-cache
via Promises. For environments not using cluster
, the class will provide a Promisified interface to a standard lru-cache
.
Each time you call cluster.fork()
, a new thread is spawned to run your application. When using a load balancer even if a user is assigned a particular IP and port these values are shared between the workers
in your cluster, which means there is no guarantee that the user will use the same workers
between requests. Caching the same objects in multiple threads is not an efficient use of memory.
LRU Cache for Clusters as Promised stores a single lru-cache
on the master
thread which is accessed by the workers
via IPC messages. The same lru-cache
is shared between workers
having a common master
, so no memory is wasted.
When creating a new instance and cluster.isMaster === true
the shared cache is checked based on the and the shared cache is populated, it will be used instead but acted on locally rather than via IPC messages. If the shared cache is not populated a new LRUCache instance is returned.
install
npm install --save lru-cache-for-clusters-as-promised
yarn add lru-cache-for-clusters-as-promised
options
namespace: string
, default "default"
;
- The namespace for this cache on the master thread as it is not aware of the worker instances.
timeout: integer
, default 100
.
- The amount of time in milliseconds that a worker will wait for a response from the master before rejecting the
Promise
.
failsafe: string
, default resolve
.
- When a request times out the
Promise
will return resolve(undefined)
by default, or with a value of reject
the return will be reject(Error)
.
max: number
- The maximum items that can be stored in the cache
maxAge: milliseconds
- The maximum age for an item to be considered valid
stale: true|false
- When
true
expired items are return before they are removed rather than undefined
prune: false|crontime string
, defaults to false
- Use a cron job on the master thread to call
prune()
on your cache at regular intervals specified in "crontime", for example "*/30 * * * * *" would prune the cache every 30 seconds (See node-cron
patterns for more info). Also works in single threaded environments not using the cluster
module. Passing false
to an existing namespace will disable any jobs that are scheduled.
parse: function
, defaults to JSON.parse
- Pass in a custom parser function to use for deserializing data sent to/from the cache. This is set on the
LRUCacheForClustersAsPromised
instance and in theory could be different per worker.
stringify: function
, defaults to JSON.stringify
- Pass in a custom stringifier function to for creating a serializing data sent to/from the cache.
! note that length
and dispose
are missing as it is not possible to pass functions
via IPC messages.
api
static functions
init(): void
- Should be called when
cluster.isMaster === true
to initialize the caches.
getInstance(options): Promise<LRUCacheForClustersAsPromised>
- Asynchronously returns an
LRUCacheForClustersAsPromised
instance once the underlying LRUCache
is guaranteed to exist. Uses the same options
you would pass to the constructor. When constructed synchronously other methods will ensure the underlying cache is created, but this method can be useful from the worker when you plan to interact with the caches directly. Note that this will slow down the construction time on the worker by a few milliseconds while the cache creation is confirmed.
getAllCaches(): { key : LRUCache }
- Synchronously returns a dictionary of the underlying
LRUCache
caches keyed by namespace. Accessible only when cluster.isMaster === true
, otherwise throws an exception.
instance functions
getCache(): LRUCache
- Gets the underlying
LRUCache
. Accessible only when cluster.isMaster === true
, otherwise throws an exception.
set(key, value, maxAge): Promise<void>
- Sets a value for a key. Specifying the
maxAge
will cause the value to expire per the stale
value or when prune
d.
setObject async (key, object, maxAge): Promise<void>
- Sets a cache value where the value is an object. Passes the values through
cache.stringify()
, which defaults to JSON.stringify()
. Use a custom parser like flatted
to cases like circular object references.
mSet({ key1: 1, key2: 2, ...}, maxAge): Promise<void>
- Sets multiple key-value pairs in the cache at one time.
mSetObjects({ key1: { obj: 1 }, key2: { obj: 2 }, ...}, maxAge): Promise<void>
- Sets multiple key-value pairs in the cache at one time, where the value is an object. Passes the values through
cache.stringify()
, see cache.setObject()
;
get(key): Promise<string | number | null | undefined>
- Returns a value for a key.
getObject(key): Promise<Object | null | undefined>
- Returns an object value for a key. Passes the values through
cache.parse()
, which defaults to JSON.parse()
. Use a custom parser like flatted
to cases like circular object references.
mGet([key1, key2, ...]): Promise<{key:string | number | null | undefined}?>
- Returns values for multiple keys, results are in the form of
{ key1: '1', key2: '2' }
.
mGetObjects([key1, key2, ...]): Promise<{key:Object | null | undefined}?>
- Returns values as objects for multiple keys, results are in the form of
{ key1: '1', key2: '2' }
. Passes the values through cache.parse()
, see cache.getObject()
.
peek(key): Promise<string | number | null | undefined>
- Returns the value for a key without updating its last access time.
del(key): Promise<void>
- Removes a value from the cache.
mDel([key1, key2...]): Promise<void>
- Removes multiple keys from the cache..
has(key): Promise<boolean>
- Returns true if the key exists in the cache.
incr(key, [amount]): Promise<number>
- Increments a numeric key value by the
amount
, which defaults to 1
. More atomic in a clustered environment.
decr(key, [amount]): Promise<number>
- Decrements a numeric key value by the
amount
, which defaults to 1
. More atomic in a clustered environment.
reset(): Promise<void>
- Removes all values from the cache.
keys(): Promise<Array<string>>
- Returns an array of all the cache keys.
values(): Promise<Array<string | number>>
- Returns an array of all the cache values.
dump()
- Returns a serialized array of the cache contents.
prune(): Promise<void>
- Manually removes items from the cache rather than on get.
length(): Promise<number>
- Return the number of items in the cache.
itemCount(): Promise<number>
- Return the number of items in the cache - same as
length()
.
max([max]): Promise<number | void>
- Get or update the
max
value for the cache.
maxAge([maxAge]): Promise<number | void>
- Get or update the
maxAge
value for the cache.
allowStale([true|false]): Promise<boolean | void>
- Get or update the
allowStale
value for the cache (set via stale
in options). The stale()
method is deprecated.
execute(command, [arg1, arg2, ...]): Promise<any>
- Execute arbitrary command (
LRUCache
function) on the cache, returns whatever value was returned.
example usage
Master
require('lru-cache-for-clusters-as-promised').init();
Worker
const LRUCache = require('lru-cache-for-clusters-as-promised');
let cache = new LRUCache({
namespace: 'users',
max: 50,
stale: false,
timeout: 100,
failsafe: 'resolve',
});
const user = { name: 'user name' };
const key = 'userKey';
(async function() {
cache = await LRUCache.getInstance({ });
await cache.set(key, user);
console.log('set the user to the cache');
const cachedUser = await cache.get(key);
console.log('got the user from cache', cachedUser);
const size = await cache.length();
console.log('user cache size/length', size);
await cache.reset();
console.log('the user cache is empty');
const itemCount = await cache.itemCount();
console.log('user cache size/itemCount', itemCount);
}());
LRUCache.getInstance({ })
.then((myCache) =>
myCache.set(key, user)
.then(() =>
myCache.get(key)
)
)
Use a custom object parser for the cache to handle cases like circular object references that JSON.parse()
and JSON.stringify()
cannot, or use custom revivers, etc.
const flatted = require('flatted');
const LRUCache = require('lru-cache-for-clusters-as-promised');
const cache = new LRUCache({
namespace: 'circular-objects',
max: 50,
parse: flatted.parse,
stringify: flatted.stringify,
});
const a = { b: null };
const b = { a };
b.a.b = b;
await cache.setObject(1, a);
const c = await cache.getObject(1);
if (a == c && a.b === c.b) {
console.log('yes they are the same!');
}
process flow
Clustered cache on master thread for clustered environments
Promisified for non-clustered environments