Overview
ActionHero ships with the functions needed for a distributed key-value cache. You can cache strings, numbers, arrays and objects (anything that responds to JSON.stringify).
The cache's redis server is defined by api.config.redis. It is possible to use fakeredis.
Cache Methods
api.cache.save
- Invoke:
api.cache.save(key, value, expireTimeMS, next)expireTimeMScan be null if you never want the object to expire
- Callback:
next(error, newObject)errorwill be null unless the object can't be saved (perhaps out of ram or a bad object type).- overwriting an existing object will return
newObject = true
api.cache.save is used to both create new entries or update existing cache entries. If you don't define an expireTimeMS, null will be assumed, and using null will cause this cached item to never expire. Expired cache objects will be periodically swept away (but not necessarily exactly when they expire)
api.cache.load
- Invoke:
api.cache.load(key, next)orapi.cache.load(key, options, next)optionscan be{{expireTimeMS: 1234}}where the act of reading the key will reset the key's expire time- If the requested
keyis not found (or is expired), all values returned will be null.
- Callback:
next(error, value, expireTimestamp, createdAt, readAt)valuewill be the object which was saved andnullif the object cannot be found or is expiredexpireTimestamp(ms) is when the object is set to expire in system timecreatedAt(ms) is when the object was createdreadAt(ms) is the timestamp at which the object was last read withapi.cache.load. Useful for telling if another worker has consumed the object recently
api.cache.destroy
- Invoke:
api.cache.destroy(key) - Callback:
next(error, destroyed)- will be false if the object cannot be found, and true if destroyed
List Methods
api.cache implements a distributed shared list. 3 simple functions are provided to interact with this list, push, pop, and listLength. These lists are stored in Redis, and cannot be locked. That said, a push and pop operation will guarantee that one-and-only-one copy of your data is returned to whichever application acted first (when popping) or an error will be returned (when pushing).
api.cache.push
- Invoke:
api.cache.push(key, data, next)- data must be serializable via JSON.stringify
- Callback:
next(error)
api.cache.pop
- Invoke:
api.cache.pop(key, next) - Callback:
next(error, data)- data will be returned in the object form it was saved (array, object, string)
api.cache.listLength
- Invoke:
api.cache.listLength(key, next) - Callback:
next(error, length)- length will be an integer.
- if the list does not exist,
0will be returned
- if the list does not exist,
- length will be an integer.
Lock Methods
You may optionally implement locking methods along with your cache objects. This will allow one ActionHero server to obtain a lock on an object and prevent modification of it by another member of the cluster. For example you may want to first api.cache.lock a key, and then save it to prevent other nodes from modifying the object.
api.cache.lock
- Invoke:
api.cache.lock(key, expireTimeMS, next)expireTimeMSis optional, and will beexpireTimeMS = api.cache.lockDuration = api.config.general.lockDuration
- Callback:
next(error, lockOk)errorwill be null unless there was something wrong with the connection (perhaps a redis error)lockOkwill betrueorfalsedepending on if the lock was obtained.
api.cache.unlock
- Invoke:
api.cache.unlock(key, next) - Callback:
next(error, lockOk)errorwill be null unless there was something wrong with the connection (perhaps a redis error)lockOkwill betrueorfalsedepending on if the lock was removed.
api.cache.checkLock
- Invoke:
api.cache.checkLock(key,retry, next)retryis eithernullor an integer (ms) that we should keep retrying until the lock is free to be re-obtained
- Callback:
next(error, lockOk)errorwill be null unless there was something wrong with the connection (perhaps a redis error)lockOkwill betrueorfalsedepending on if the lock is currently obtainable.
api.cache.locks
- Invoke:
api.cache.locks(next) - Callback:
next(error, locks)locksis an array of all currently active locks
You can see an example of using the cache within an action in actions/cacheTest.js
Redis
The timestamps regarding api.cache.load are to help clients understand if they are working with data which has been modified by another peer (when running in a cluster).
Keep in mind that many clients/servers can access a cached value simultaneously, so build your actions carefully not to have conflicting state. You can learn more about the cache methods here. You can also review recommendations about Production Redis configurations.