Tagging system
Creating an issue in case people have the same question.
I am not fully happy with the namespace system we have. Not enough for easy invalidation. So I would love to have tags and it's planned, but it's quite a tricky thing to nail down, especially in bentocache, where we have a lot of different features
I've been doing quite a bit of research on the topic and should try an implementation when I have some time. The API will be super simple:
await bento.getOrSet({
key: 'foo',
factory: getFromDb(),
tags: ['tag-1', 'tag-2']
});
await bento.set({
key: 'foo',
tags: ['tag-1']
});
Then, we could delete all entries tagged with tag-1 using:
await bento.delete({ tag: 'tag-1' });
This would remove all entries that have the tag-1 tag.
It's likely that this tagging system will deprecate the current namespace system we have. I think they would become useless once we have tags. We would keep namespaces until v2, but they would be marked as deprecated via JSDoc
Super happy to see this issue. Allow me to propose a mechanism that I believe is universal for any kind o production system: https://github.com/mcollina/async-cache-dedupe#invalidation.
It's actually quite similar to the tags you illustrated, except that in the proposed solution the tags can be computed based on the factory result.
Suppose I have a Product model that can be assigned to many Categories. I then do a query for Product:1 that is currently assigned to ['Category:1', 'Category:2']. I then mark Category:2 as archived in other part of the system, and I'd like to invalidate all Product queries/caches that referenced the Category:1.
That's impossible to tell with static tags without the context of factory result. But from my understanding, the difficult part is tag-based invalidation. Collecting tags (or references) from a callback instead of array shouldn't present too many complications?
Yup absolutely, I should have included it in my first comment. In fact, the tags will be compatible with the adaptive caching system we have today. So :
const product = await bento.getOrSet({
key: 'product:1',
factory: async (ctx) => {
const product = await getFromDb(1)
ctx.setTags(product.categories.map((category) => category.name))
return product
}
});
Lemme know if it could suit you
Beautiful 😍 I believe that solves my last trouble with the library, and would make bentocache the ultimate caching library for production-grade node apps!
In fact, such API should be sufficient to implement an automatic ORM caching layer similar to https://github.com/Suor/django-cacheops. Basically, all relations returned by the ORM are saved as references, and all updates/deletes automatically invalidate relevant results. That's definitely something out of scope of bentocache itself, but could provide very solid ground for a 3rd party integration.
Possibly, ctx.addTags would be useful to make it easier to collect tags from multiple helpers, but I guess that could be achieved with ctx.setTags([...ctx.tags, ...result.otherRelations.map(r => r.id)]).
I merged PR #57, which adds experimental support for tags 🎉 Experimental, because the feature is pretty complex. So I would really like to have some feedbacks and use it in some real world projects to be more confident about it
Next steps:
- ~~Add a new docs page on it, because the internals of the tag system, the way it works, is not ultra-conventional. This needs to be documented. Also add a warning that tags are experimental and ideally require feedback~~
- Docs available : https://bentocache.dev/docs/tagging
- ~~Release [email protected] with tags~~
- Keep this issue open to track feedback on tags
Still not sure if we should deprecated namespace. Lemme know if you have any thoughts
Also @wodCZ and @dunhamjared thanks a lot for the sponsorship 🙏
1.2.0 released with docs
Release notes : https://github.com/Julien-R44/bentocache/releases/tag/bentocache%401.2.0 Docs : https://bentocache.dev/docs/tagging
If you encounter any bugs with tagging or have any feedback, please let me know!
Hello @Julien-R44
There's a bug with .has method
After deleting by tag, .has method stills return true
const key = 'user:1';
const tags = ['userTag'];
await bentoCache.set({
key,
value: 'lol',
tags,
});
await bentoCache.deleteByTag({ tags });
await bentoCache.has({ key }); // This returns true
@Maged-Zaki Thanks, indeed a bug. Fixed by #65
now that it's fixed, we should close this @Julien-R44