Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cache-service-cache-module

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cache-service-cache-module - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

153

cacheModule.js

@@ -5,7 +5,10 @@ /**

* @param config: {
* type: {string | 'cache-module'}
* verbose: {boolean | false},
* expiration: {integer | 900},
* readOnly: {boolean | false},
* checkOnPreviousEmpty {boolean | true}
* type: {string | 'cache-module'}
* verbose: {boolean | false},
* expiration: {integer | 900},
* readOnly: {boolean | false},
* checkOnPreviousEmpty {boolean | true},
* backgroundRefreshIntervalCheck {boolean | true},
* backgroundRefreshInterval {integer | 60000},
* backgroundRefreshMinTtl {integer | 70000}
* }

@@ -21,9 +24,19 @@ */

self.checkOnPreviousEmpty = (typeof config.checkOnPreviousEmpty === 'boolean') ? config.checkOnPreviousEmpty : true;
self.backgroundRefreshIntervalCheck = (typeof config.backgroundRefreshIntervalCheck === 'boolean') ? config.backgroundRefreshIntervalCheck : true;
self.backgroundRefreshInterval = config.backgroundRefreshInterval || 60000;
self.backgroundRefreshMinTtl = config.backgroundRefreshMinTtl || 70000;
var cache = {
db: {},
expirations: {}
expirations: {},
refreshKeys: {}
};
var backgroundRefreshEnabled = false;
log(false, 'Cache-module client created with the following defaults:', {expiration: this.expiration, verbose: this.verbose, readOnly: this.readOnly});
/**
******************************************* PUBLIC FUNCTIONS *******************************************
*/
/**
* Get the value associated with a given key

@@ -35,13 +48,15 @@ * @param {string} key

self.get = function(key, cb, cleanKey){
log(false, 'Attempting to get key:', {key: key});
if(arguments.length < 2){
throw new exception('INCORRECT_ARGUMENT_EXCEPTION', '.get() requires 2 arguments.');
}
log(false, 'get() called:', {key: key});
try {
var cacheKey = (cleanKey) ? cleanKey : key;
log(false, 'Attempting to get key:', {key: cacheKey});
var now = Date.now();
var expiration = cache.expirations[key] || this.defaultExpiration;
if(expiration && expiration > now){
var expiration = cache.expirations[key];
if(expiration > now){
cb(null, cache.db[key]);
}
else{
self.del(key);
expire(key);
cb(null, null);

@@ -62,3 +77,6 @@ }

self.mget = function(keys, cb, index){
log(false, 'Attempting to mget keys:', {keys: keys});
if(arguments.length < 2){
throw new exception('INCORRECT_ARGUMENT_EXCEPTION', '.mget() requires 2 arguments.');
}
log(false, '.mget() called:', {keys: keys});
var values = {};

@@ -81,16 +99,31 @@ for(var i = 0; i < keys.length; i++){

* @param {integer} expiration
* @param {function} refresh
* @param {function} cb
*/
self.set = function(key, value, expiration, cb){
log(false, 'Attempting to set key:', {key: key, value: value});
self.set = function(){
if(arguments.length < 2){
throw new exception('INCORRECT_ARGUMENT_EXCEPTION', '.set() requires a minimum of 2 arguments.');
}
var key = arguments[0];
var value = arguments[1];
var expiration = arguments[2] || null;
var refresh = (arguments.length == 5) ? arguments[3] : null;
var cb = (arguments.length == 5) ? arguments[4] : arguments[3];
log(false, '.set() called:', {key: key, value: value});
try {
if(!self.readOnly){
expiration = expiration || self.defaultExpiration;
var exp = (expiration) ? (expiration * 1000) : self.defaultExpiration;
cache.expirations[key] = Date.now() + exp;
expiration = (expiration) ? (expiration * 1000) : self.defaultExpiration;
var exp = expiration + Date.now();
cache.expirations[key] = exp;
cache.db[key] = value;
if(cb) cb();
if(refresh){
cache.refreshKeys[key] = {expiration: exp, lifeSpan: expiration, refresh: refresh};
if(!backgroundRefreshEnabled){
backgroundRefreshInit();
}
}
}
} catch (err) {
log(true, 'Set failed for cache of type ' + self.type, {name: 'NodeCacheSetException', message: err});
log(true, '.set() failed for cache of type ' + self.type, {name: 'CacheModuleSetException', message: err});
}

@@ -106,3 +139,6 @@ }

self.mset = function(obj, expiration, cb){
log(false, 'Attempting to mset data:', {data: obj});
if(arguments.length < 1){
throw new exception('INCORRECT_ARGUMENT_EXCEPTION', '.mset() requires a minimum of 1 argument.');
}
log(false, '.mset() called:', {data: obj});
for(key in obj){

@@ -128,8 +164,12 @@ if(obj.hasOwnProperty(key)){

self.del = function(keys, cb){
log(false, 'Attempting to delete keys:', {keys: keys});
if(arguments.length < 1){
throw new exception('INCORRECT_ARGUMENT_EXCEPTION', '.del() requires a minimum of 1 argument.');
}
log(false, '.del() called:', {keys: keys});
if(typeof keys === 'object'){
for(var i = 0; i < keys.length; i++){
var key = keys[i];
cache.db[key] = undefined;
cache.expirations[key] = undefined;
delete cache.db[key];
delete cache.expirations[key];
delete cache.refreshKeys[key];
}

@@ -139,4 +179,5 @@ if(cb) cb(null, keys.length);

else{
cache.db[keys] = undefined;
cache.expirations[keys] = undefined;
delete cache.db[keys];
delete cache.expirations[keys];
delete cache.refreshKeys[keys];
if(cb) cb(null, 1);

@@ -151,5 +192,6 @@ }

self.flush = function(cb){
log(false, 'Attempting to flush all data.');
log(false, '.flush() called');
cache.db = {};
cache.expirations = {};
cache.refreshKeys = {};
if(cb) cb();

@@ -159,2 +201,61 @@ }

/**
******************************************* PRIVATE FUNCTIONS *******************************************
*/
/**
* Delete a given key from cache.db and cache.expirations but not from cache.refreshKeys
* @param {string} key
*/
function expire(key){
delete cache.db[key];
delete cache.expirations[key];
}
/**
* Initialize background refresh
*/
function backgroundRefreshInit(){
if(!backgroundRefreshEnabled){
backgroundRefreshEnabled = true;
if(self.backgroundRefreshIntervalCheck){
if(self.backgroundRefreshInterval > self.backgroundRefreshMinTtl){
throw new exception('BACKGROUND_REFRESH_INTERVAL_EXCEPTION', 'backgroundRefreshInterval cannot be greater than backgroundRefreshMinTtl.');
}
}
setInterval(function(){
backgroundRefresh();
}, self.backgroundRefreshInterval);
}
}
/**
* Refreshes all keys that were set with a refresh function
*/
function backgroundRefresh(){
for(key in cache.refreshKeys){
if(cache.refreshKeys.hasOwnProperty(key)){
var data = cache.refreshKeys[key];
if(data.expiration - Date.now() < self.backgroundRefreshMinTtl){
data.refresh(key, function (err, response){
if(!err){
self.set(key, response, data.lifeSpan, data.refresh, noop);
}
});
}
}
}
}
/**
* Instantates an exception to be thrown
* @param {string} name
* @param {string} message
* @return {exception}
*/
function exception(name, message){
this.name = name;
this.message = message;
}
/**
* Error logging logic

@@ -172,4 +273,6 @@ * @param {boolean} isError

}
function noop(){}
}
module.exports = cacheModule;

2

package.json
{
"name": "cache-service-cache-module",
"version": "1.0.0",
"version": "1.1.0",
"description": "A cache plugin for cache-service.",

@@ -5,0 +5,0 @@ "main": "cacheModule.js",

@@ -6,2 +6,11 @@ # cache-service-cache-module

#### Features
* Background refresh
* No external dependencies
* Robust API
* Built-in logging with a `verbose` flag.
* Compatible with `cache-service` and `superagent-cache`
* Excellent `.mset()` implementation which allows you to set expirations on a per key, per function call, and/or per `cache-service-cache-module` instance basis.
# Basic Usage

@@ -22,12 +31,6 @@

# Benefits of Using `cache-service-cache-module`
# Cache Module Configuration Options
If you're using `cache-service-cache-module` with `cache-service`, the benefits are obvious. However, there are also a couple of reasons you might like it as a standalone in-memory cache module:
`cache-service-cache-module`'s constructor takes an optional config object with any number of the following properties:
* No external dependencies.
* It features an excellent `.mset()` implementation which allows you to set expirations on a per key, per function call, and/or per `cache-service-cache-module` instance basis.
* Built-in logging with a `verbose` flag.
# Cache Module Configuration Options
## type

@@ -42,3 +45,3 @@

The expiration to include when executing cache set commands. Can be overridden via `.set()`'s optional expiraiton param.
The expiration to include when executing cache set commands. Can be overridden via `.set()`'s optional `expiraiton` param.

@@ -49,2 +52,25 @@ * type: int

## backgroundRefreshInterval
How frequently should all background refresh-enabled keys be scanned to determine whether they should be refreshed. For a more thorough explanation on `background refresh`, see the [Using Background Refresh](#using-background-refresh) section.
* type: int
* default: 60000
* measure: milliseconds
## backgroundRefreshMinTtl
The maximum ttl a scanned background refresh-enabled key can have without triggering a refresh. This number should always be greater than `backgroundRefreshInterval`.
* type: int
* default: 70000
* measure: milliseconds
## backgroundRefreshIntervalCheck
Whether to throw an exception if `backgroundRefreshInterval` is greater than `backgroundRefreshMinTtl`. Setting this property to false is highly discouraged.
* type: boolean
* default: true
## verbose

@@ -81,9 +107,12 @@

## .set(key, value [, expiraiton, callback])
## .set(key, value, [expiraiton], [refresh(key, cb)], [callback])
> See the [Using Background Refresh](#using-background-refresh) section for more about the `refresh` and `callback` params.
Set a value by a given key.
* key: type: string
* callback: type: function
* value: type: string || objects
* expiration: type: int, measure: seconds
* refresh: type: function
* callback: type: function

@@ -103,3 +132,3 @@

## .del(keys [, callback (err, count)])
## .del(keys, [callback (err, count)])

@@ -118,1 +147,43 @@ Delete a key or an array of keys and their associated values.

* callback: type: function
# Using Background Refresh
With a typical cache setup, you're left to find the perfect compromise between having a long expiration so that users don't have to suffer through the worst case load time, and a short expiration so data doesn't get stale. `cache-service-cache-module` eliminates the need to worry about users suffering through the longest wait time by automatically refreshing keys for you. Here's how it works:
#### How do I turn it on?
By default, background refresh is off. It will turn itself on the first time you pass a `refresh` param to `.set()`.
#### Configure
There are three options you can manipulate. See the API section for more information about them.
* `backgroundRefreshInterval`
* `backgroundRefreshMinTtl`
* `backgroundRefreshIntervalCheck`
#### Use
Background refresh is exposed via the `.set()` command as follows:
```javascript
cacheModule.set('key', 'value', 300, refresh, cb);
```
If you want to pass `refresh`, you must also pass `cb` because if only four params are passed, `cache-service-cache-module` will assume the fourth param is `cb`.
#### The Refresh Param
###### refresh(key, cb(err, response))
* key: type: string: this is the key that is being refreshed
* cb: type: function: you must trigger this function to pass the data that should replace the current key's value
The `refresh` param MUST be a function that accepts `key` and a callback function that accepts `err` and `response` as follows:
```javascript
var refresh = function(key, cb){
var response = goGetData();
cb(null, response);
}
```
var expect = require('expect');
var cModule = require('../../cacheModule');
var cacheModule = new cModule();
var cacheModule = new cModule({
backgroundRefreshInterval: 500
});

@@ -72,2 +74,15 @@ var key = 'key';

});
it('Using background refresh should reset a nearly expired key', function (done) {
var refresh = function(key, cb){
cb(null, 1);
}
cacheModule.set(key, value, 1, refresh, function (err, result){
setTimeout(function(){
cacheModule.get(key, function (err, response){
expect(response).toBe(1);
done();
});
}, 1500);
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc