redis-cache-decorator
v1.3.1
Published
Decorator to cache/lock expensive functions with Redis
Downloads
12
Maintainers
Readme
redis-cache-decorator
A decorator to cache your functions. Features:
- Uses Redis caching, expiration, and pub/sub.
- Concurrency locking - if the function is being run elsewhere with the same arguments, it will wait for the result of that function instead of executing again.
- Caching - caches results for as long as you want. If you set
ttl=0
, then you're just this library for concurrency locking, which is completely fine. - Timeouts - throws when executing or waiting for a function call takes too long
- Only tested with ioredis
Use Cases:
- Race conditions
- API calls with rate limits
- Expensive database calls
- Expensive function calls
Example
Here's a function that caches all your queries.
const assert = require('assert')
const Redis = require('ioredis')
const pg = require('pg-then')
const pool = pg.Pool(process.env.POSTGRES_URI)
const CreateCacheDecorator = require('redis-cache-decorator')({
client: Redis.createClient(),
subscriber: Redis.createClient()
})
const fn = CreateCacheDecorator({
namespace: 'crazy-database-call',
})((query, values) => {
return db.query(query).then(result => result.rows)
})
fn(`
SELECT *
FROM users
WHERE id = $1
`, [
1
]).then(users => {
assert(Array.isArray(users))
})
API
const CreateCacheDecorator = require('redis-cache-decorator')(options)
Creates a constructor with the following options:
client <required>
- a redis client for GET/SET/PUBLISH, etc.subscriber <required>
- a redis client forPSUBSCIRBE
namespace = ''
- a prefix for all the eventsencoding = 'json'
- how data is encoded between redis and node.js. Supported values are:json
- the defaultstring
buffer
ttl = '30s'
- the TTL expiration in seconds.timeout = '30s'
- how long to wait for the function to execute.pollFactor = 1 / 10
- the fraction of the timeout to poll. For example, a30s
timeout with a1 / 10
factor means that redis is polled for new changes every 3 seconds.minimumPollInterval = '100ms'
- the minimum frequency of polling so you don't end up spamming rediscreateTimeoutError = () => <Error>{ message: 'Timed out!', code: 'RCDTIMEDOUT' }
- the function called to create a timeout error. By default, you can check for timeout errors by checkingif (err.code === 'RCDTIMEDOUT')
.onError = err => console.error(err.stack)
- an error handler for redis network errors.disabled = false
- disable this decorator, specifically useful for testing.
const decorate = CreateCacheDecorator(options)
Create a decorator with a set of options.
namespace <required>
- a namespace for this decoratorpollInterval
- by default, calculated fromtimeout
,pollFactor
, andminimumPollInterval
, but you can set this yourself.ttl
timeout
pollFactor
minimumPollInterval
createTimeoutError
onError
const decoratedFunction = decorate(fn)
Decorates the function. The decorated function will have the same API as the original function.
- The function should return a value or a
Promise
that can beJSON.stringify()
d. - The function can be synchronous or asynchronous.
this
is not supported. Do not accessthis
within the function. The primary reason is that it's difficult to decide how to cache.
const job = decoratedFunction(...args)
Execute the decorated function. Will always return a Promise
that resolves to the value.
In addition, the promise will have the following properties:
.hash
- hash of the arguments for this job.
job.then(value => {}, err => {})
Resolve the promise to retrieve the results of the job.
const hash = decoratedFunction.createHash(...args)
Create the hash string for the specified arguments.
decoratedFunction.set(hash, value).then(value => {})
Manually set the value of a hash.
Streams
If a stream is returned, the values will automatically be buffered.
encoding='json'
- the stream will be concatenated as an object stream -> array. If the stream is not an object stream, it will throw.encoding='string'
- the stream will be buffered into a string.encoding='buffer'
- the stream will be buffered into aBuffer()
instance.