Closed damienleroux closed 6 years ago
Hi there!
I originally intended for each of the cache modules available for use with cache-service
to have a nameSpace
property. When using those caches individually, you would be able set namespaces on them. When using cache-service
, you would be able to assign a namespace that would be set to all child caches. Each child cache would then prefix cache keys and logs with the cache namespace. (Currently only cache-service-redis
prefixes keys with the provided nameSpace
.)
However, it appears that, at this point, namespace is mostly just left over and unimplemented. Additionally, in retrospect, it doesn't make much sense for cache-service
's namespace to overwrite all child cache namespaces.
If I were to update my nameSpace
implementation, I would want child cache nameSpace
properties to trump the cache-service
nameSpace
property. In fact, I would probably just remove nameSpace
from cache-service
and just have users manually set nameSpace
on all child caches.
This would require updates to:
cache-service
to remove nameSpace
cache-service-redis
to log nameSpace
cache-service-cache-module
to prefix keys with and log nameSpace
cache-service-mem-cached
(this would be a PR since I don't own this repo)cache-service-file-cache
(this would be a PR since I don't own this repo)I would most likely not update cache-service-node-cache
. I would like to deprecate this repo in favor of
cache-service-cache-module
.
What are your thoughts?
Hello,
Thank you for you answer that enlightened me.
I agree that configuring nameSpace
should be handle by cache-service
as it makes more sense that each cache should handle it own nameSpace
.
I may not know yet all the ins and outs of cache-service
, but I believe it useful to retrieve or to update data from multiple caches, without having to know the cache that keeps the targeted key and corrsponding response.
I would have believed that nameSpace
was used to target, when required, a specific cache.
Example of what I would have had in mind for cache-service
:
var nodeCache = new nodeCacheModule({nameSpace: 'nodeNameSpace'});
var redisCache = new redisModule({nameSpace: 'redisNameSpace'});
var cacheModules = [nodeCache, redisCache];
var cacheService = new cs({}, cacheModules);
//target a key without a specific namespace
cacheService.get(key, myCallback);
//target a key with a specific namespace
cacheService.get(key, myCallback, 'nodeNameSpace');
Another use case that would match my needs: I need to create dynamically caches with their own namespace. This is what I would have wanted:
var cacheService = new cs({}, []);
//create cache for damien
var nodeCache = new nodeCacheModule({nameSpace: 'damien'});
cacheService.addCache(nodeCache);
//create cache for jpodwys
var nodeCache = new nodeCacheModule({nameSpace: 'jpodwys'});
cacheService.addCache(nodeCache);
//add keys for damien
cacheService.set('a', 'aa', undefined, undefined , undefined, 'damien');
cacheService.set('b', 'bb', undefined, undefined , undefined, 'damien');
//add keys for jpodwys
cacheService.set('a', 'AA', undefined, undefined , undefined, 'jpodwys');
cacheService.set('c', 'CC', undefined, undefined , undefined, 'jpodwys');
//target a key for damien
cacheService.get('a', myCallback, 'damien'); // found value : 'aa'
//target a key for all : returns several values for each found namespace
cacheService.get('a', myCallback); // found values : { damien: 'aa', jpodwys: 'AA'}
//delete damien's cache
cacheService.deleteCache('damien');
As you can see with this example, I need a solution to handle several caches with their own namespace and I think that cache-service
should provide it.
From what I understand, the original nameSpace
that you thought is serving a different purpose. I don't think that nameSpace
should be applied to cache keys but should be used in a collection to separate caches.
Let me know if I miss something or if I misunderstood the intended cache-service
behavior.
Thank you
I apologize, this is a big response.
If I understand correctly, you want the ability to call public methods on a single cache module within cache-service
based on the nameSpace
you gave that individual cache. Does that sounds right?
Let me start off by saying I'm not interested in adding arguments to public methods at this time. I would rather you just fetch the cache you want and call one of its public methods directly.
In fact, in a manner of speaking, there's already a way to do just that. Because you provided the caches to cache-service
, you know the index of the cache you want. As such, you can call cacheService.caches[index].set(key, value);
.
If that's insufficient for your needs, a small utility function should do the trick. Perhaps something like this:
function getCacheByNameSpace(caches, nameSpace){
for(var i = 0; i < caches.length; i++){
if(caches[i].nameSpace === nameSpace){
return caches[i];
}
}
return null;
}
You could use the above function like this:
var individualCache = getCacheByNameSpace(cacheService.caches, nameSpace);
if(individualCache){
individualCache.set(key, value);
}
I might consider baking this sort of behavior into a new public method so you could call cacheService.getCacheByNameSpace('damien').set(key, value);
.
The only action you mentioned above that my recommendations here would not satisfy is this one:
cacheService.get('a', myCallback); // found values : { damien: 'aa', jpodwys: 'AA'}
cache-service
is not intended to fetch a single key from multiple caches. Rather, it finds the first matching key in a list of caches. (More on its original intent at the bottom of this comment.)
When you say you want to be able to write to and query from multiple caches based on more than one property (namely key
and nameSpace
), it starts to sound like you need a database rather than a key/value cache implementation.
For example, the pseudo-code examples you provided above basically boil down to these generic database queries:
set key to value where nameSpace = damien
get all where key = username
I may be mistaken about what you need, but if this sounds like the kind of functionality you're hoping for, MySQL, Mongo, or even Redis can support these use cases far better than cache-service
.
If I've misunderstood, please correct me.
cache-service
's Original IntentI originally intended cache-service
to be a tiered caching solution. By that, I mean that each cache serves as a level of redundancy for the prior layer.
Here's an example:
Let's say your cache lives on your web server. Awesome! Caching on your web server makes responses as fast as they can be. However, you're going to encounter some issues:
As a result, you decide to move your cache off of your server and into redis. Now your data persists between server restarts and all instances of your server benefit from it. However, your cache lookups are now slightly slower than they used to be.
cache-service
gives you the speed of storing your cache locally with the redundancy of storing your cache remotely. It works by allowing you to have a primary in-memory cache module backed by a secondary remote cache module. Any time you set a cache key, it gets set to all caches passed to cache-service
. Additionally, any time you read from cache-service
, if the key isn't in the first cache but is in the second cache, cache-service
writes that key and value to the first cache so that they will be available in-memory the next time you need them.
Additionally, if you have memory capacity concerns, you can decrease your primary cache's expiration so keys stored in memory are short-lived. Doing this allows you to keep only your most used keys in memory with all the others in your remote cache.
Hello,
Thank you for your time. You have perfectly well resumed my intents. I actually end up with a simple solution that looks like your example except that I didn't use cache-service
at all but create a simple collection that contained all caches:
import CsNodeCache from 'cache-service-node-cache';
const caches = {};
export function getCache(namespaces) {
if (!caches[namespaces]) {
//see https://github.com/jpodwys/cache-service-node-cache#basic-usage
caches[namespaces] = new CsNodeCache();
}
return caches[namespaces];
}
export function getCacheInfo(namespaces, req) {
//remove req.headers to keep only "accept" and "accept-language"
const headersToRemove = Object.keys(req.headers);
const headersToKeep = ["accept", "accept-language"];
headersToKeep.map(headerToKeep => {
const i = headersToRemove.indexOf(headerToKeep);
if (i > -1) {
headersToRemove.splice(i, 1);
}
});
return {
cache: getCache(namespaces),
config: {
pruneHeader: headersToRemove
}
};
}
export function deleteCache(namespaces) {
if (caches[namespaces]) {
//see https://github.com/jpodwys/cache-service-node-cache#flushcb
caches[namespaces].flush();
delete (caches[namespaces]);
}
}
And I agree with you about that searching multiple results through multiple caches sounds like database queries ^^. The idea crossed my mind too.
I misunderstood the primary goal of cache-service
that's why your last explanation has been very enlightening. For now, I'm making only tests locally to server instances but when I'll put the cache into Redis, I think cache-service
will be very useful.
I close the issue. Thank you
Hello.
The document says
nameSpace
can be set on cache service creation.nameSpace
?nameSpace
s to segment my cache in separated zone ?Thank you