Skip to content

Check your caching layer before running your promises

License

Notifications You must be signed in to change notification settings

camsjams/node-treasury

Repository files navigation

Node Treasury: A promise to check for data in your cache layer first

Check your caching layer before running your promises.

master: master develop: develop

Version 2.0.0+

  • Removes Promise factory overrides
  • Provides TypeScript definitions
  • Performance Optimized
  • Upgraded dependencies

Platforms / Technologies

Currently supported cache adapters

Install

  $ npm install treasury --save

Usage

Constructor Options

var Treasury = require('treasury');

// default options for main class wrapper
var treasury = new Treasury({
    client: null,
    namespace: 'Treasury',
    ttl: tauist.s.fiveMinutes
});

option: client

If null, Treasury will default to in-memory cache with managed expiration.

You can also pass a redis or memcached client in:

var Memcached = require('memcached');
var client = new Memcached();
// please see adapters section for all currently supported adapters
var redis = require('redis');
var client = redis.createClient();

var treasury = new Treasury({client: client});

option: namespace

This is used to set a default namespace in the event that the invest function is invoked without a namespace option.

option: ttl

The default time-to-live for any cached objects, which will be used in the event that the invest function is invoked without a ttl option. It is recommended to utilize the Tauist package to ease your reuse of expiration amounts.

Treasury.invest(thePromise, options)

The invest function is used to wrap cache logic around a Promise, where the cache provider is checked for the data first before running the code for the promised value. If the cache cannot retrieve the data, the Promise is invoked and then the successfully promised value is stored in cache for later use.

The first parameter is the promise that you wish to wrap with this logic.

treasury.invest(doTheThingToReallyGetData);

Additionally, you may utilize the options parameter to customize the cache usage for this invest call.

treasury.invest(doTheThingToReallyGetData, {
    namespace: 'aCustomCachePrefix',
    ttl: 'in minutes'
});

option: namespace

This is used to set the namespace for this wrapped Promise. It will fall back to the default Treasury namespace option if not set.

option: ttl

This is used to set the time-to-live for this wrapped Promise. It will fall back to the default Treasury default ttl option if not set.

using invest() with bind

When using the Function.prototype.bind() method to curry a new function with some arguments, please advise that you need to pass these into the options parameter in order for Treasury to properly differentiate that invocation compared to others.

In this example, id is the main parameter to doTheThingToReallyGetData, so it is bound for the Promise to be called. Additionally it is passed as a property to the options object to identify it for a unique cache later on.

treasury.invest(doTheThingToReallyGetData.bind(null, id), {id: id});

Treasury.divest(options)

The divest function is used to manually delete or invalidate a cached item. It expects the same options object used by the invest function in order to find the proper row of data to remove.

treasury.divest({
    namespace: 'aCustomCachePrefix',
    ttl: 'in minutes'
});

option: namespace

This is used to find the namespace for this wrapped Promise. It will fall back to the default Treasury namespace option if not set.

Basic usage - see full code in the examples

Here is a basic sample of "before" code using a redis cache layer.

var key = 'MyModel:' + id;  // you have to manage the keys!
var cacheClient = redis.createClient();

cacheClient.getAsync(key) // you have to promisify the cache client!
      .then(function(data) {
          if (data) {
              // you have to manage the object --> JSON string!
              return Promise.resolve(JSON.parse(data));
          } else {
              return Promise.reject('NO_CACHE');
          }
      })
      .catch(function(err) {
          if (err !== 'NO_CACHE') {
              // you have to manage error filtering!
              return Promise.reject(err);
          } else {
              return doTheThingToReallyGetData({id: id})
                  .then(function(modelData) {
                      // return data
                      // also cache
                      // you have to manage the JSON string --> object!
                      return cacheClient.setexAsync(key, 10, JSON.stringify(modelData))
                          .then(function() {
                              return modelData;
                          });
                  });
          }
      })
      .then(function(data) {
          console.log('found data:', data);
      })
      .catch(function(err) {
          console.log('could not find data, err:', err);
      });

Wouldn't it be great to just do this?

treasury.invest(doTheThingToReallyGetData({id: id}))
    .then(function(data) {
        console.log('found data:', data);
    })
    .catch(function(err) {
        console.log('could not find data, err:', err);
    });

Pull Requests

In order to properly run the tests for this repo, on top of the npm install, you will need the dependencies in Circle CI config. All PRs require passing eslint and code coverage and updated/added/passing unit and integration tests.

Notes

I tried really hard not to use a cache/cash pun when writing node-treasury.

This project was inspired by the excellent Node.js callback wrapper souvenir.

About

Check your caching layer before running your promises

Resources

License

Stars

Watchers

Forks

Packages

No packages published