jpodwys / cache-service-redis

A redis plugin for cache-service.
MIT License
7 stars 9 forks source link

cache-service-redis

Features

Basic Usage

Require and instantiate

var csRedis = require('cache-service-redis');

var cacheModuleConfig = {redisEnv: 'REDISCLOUD_URL'};
var redisCache = new csRedis(cacheModuleConfig);

Cache!

redisCache.set('key', 'value');

Cache Module Configuration Options

cache-service-redis's constructor takes an optional config object with any number of the following properties:

type

An arbitrary identifier you can assign so you know which cache is responsible for logs and errors.

defaultExpiration

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

redisData

This is the most generic way to pass in your redis configuraiton options.

Example

var redisData = {
  port: myRedisPort,
  hostname: myRedisHostname,
  auth: myRedisAuth
}

redisUrl

If you have all of your redis params already prepared as a URL in the following format: http://uri:password@hostname:port, then you can simply pass that URL with the object key redisUrl.

redisEnv

If you have a redis URL contained in an env variable (in process.env[redisEnv]), cache-service can retrieve it for you if you pass the env variable name with the object key redisEnv.

JSON

By default, cache-service-redis attempts to JSON.stringify and JSON.parse values on set and get respectively. If it fails, it just sets/gets the raw value. This may not always meet your needs. As such, you can provide your own object with stringify and parse public functions.

redisMock

If you want to test your cache-service-redis implementation, you can pass a redis mock with this key and cache-service-redis will consume it for testing purposes. See the Using A Redis Mock section for a more throrough explanation.

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 section.

backgroundRefreshMinTtl

The maximum ttl a scanned background refresh-enabled key can have without triggering a refresh. This number should always be greater than backgroundRefreshInterval.

backgroundRefreshIntervalCheck

Whether to throw an exception if backgroundRefreshInterval is greater than backgroundRefreshMinTtl. Setting this property to false is highly discouraged.

verbose

When used with cache-service, this property is overridden by cache-service's verbose value.

When false, cache-service-redis will log only errors. When true, cache-service-redis will log all activity (useful for testing and debugging).

logJsonParseFailures

This module automatically attempts to JSON.stringify values on set and JSON.parse values on get. In the event that either JSON function throws an error, the module assums the value being set or retrieved was not JSON and returns it as is. If you know you will only ever set and retrieve JSON and would therefore like errors to be logged when the JSON functions throw them, set this property to true.

API

Although this is a redis wrapper, its API differs in some small cases from redis's own API both because the redis API is sometimes dumb and because all cache-service-compatible cache modules match cache-service's API.

.get(key, callback (err, response))

Retrieve a value by a given key.

.mget(keys, callback (err, response))

Retrieve the values belonging to a series of keys. If a key is not found, it will not be in response.

.set(key, value, [expiration], [refresh(key, cb)], [callback])

See the Using Background Refresh section for more about the refresh and callback params.

Set a value by a given key.

.mset(obj, [expiration], [callback])

Set multiple values to multiple keys

This function exposes a heirarchy of expiration values as follows:

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

Delete a key or an array of keys and their associated values.

.flush([cb])

Flush all keys and values.

.db

This is the underlying node_redis instance. If needed, you can access redis functions I haven't abstracted.

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-redis eliminates the need to worry about users suffering through the longest wait time by automatically refreshing keys for you. Here's how it works:

cache-service-redis employs an intelligent background refresh algorithm that makes it so only one dyno executes a background refresh for any given key. You should feel confident that you will not encounter multiple dynos refreshing a single key.

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.

Use

Background refresh is exposed via the .set() command as follows:

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-redis will assume the fourth param is cb.

The Refresh Param

refresh(key, cb(err, response))

The refresh param MUST be a function that accepts key and a callback function that accepts err and response as follows:

var refresh = function(key, cb){
  var response = goGetData();
  cb(null, response);
}

Using A Redis Mock

You're likely to want to test your implementation of cache-service-redis. In order to write tests that will run anywhere, you'll need to use a redis mock. I recommend using redis-js. cache-service-redis natively supports mock usage as follows:

var redisMock = require('redis-js');
var rcModule = require('cache-service-redis');
var redisCache = new rcModule({
  redisMock: redisMock,
  backgroundRefreshInterval: 500
});

Using with AWS Lambda

If you use cache-service-redis inside of AWS Lambda, ensure you follow this example so that your lambda process will terminate when complete.

exports.handler = function (event, context, callback) {
  cache.get(key, function (err, val) {
    // handle value
    // terminate process with `context`
    return context.succeed();
    // OR terminate process with `callback`
    context.callbackWaitsForEmptyEventLoop = false;
    return callback(null);
  });
};

If you use cache-service-redis with superagent-cache or superagent-cache-plugin inside of AWS Lambda, follow this example.

exports.handler = function (event, context, callback) {
  superagent
    .get(uri)
    .use(superagentCache)
    .end(function (err, response){
      // handle response here
      // terminate process with `context`
      return context.succeed();
      // OR terminate process with `callback`
      context.callbackWaitsForEmptyEventLoop = false;
      return callback(null);
    }
  );
};