meteor-feature-requests
meteor-feature-requests copied to clipboard
Use Meteor user data from MergeBox to fill Meteor.userId(), thus bypassing the need to query the database for every request
Buy two facts, get one opinion free:
Fact: Every Meteor connection makes a subscription for the Meteor.user() document
Fact: Every subscription is cached to the server that the client is connected to into the server-side cache (MergeBox).
Opinion: Instead of querying the database every time that Meteor.user() is used, we should first try to retrieve it from the server-side cache (MergeBox).
The implementation can be really simple. If the document is in MergeBox, we can use that first. If not, we can query the database. Additionally, we can pass an argument into Meteor.user() to tell it to get the real document instead of the cache. Alternatively, for improved backwards compatibility, we could inverse this design, where Meteor.user(true) would get us the cached document instead of querying the database.
One situation where I could see this greatly improving performance is roles-based authorization and similar. We can attach roles information to the user document, publish that to the client, and then easily verify it for every Method call.
That can be a really good argument for Meteor's stateful design, and for an application that has say 10,000 concurrent users, it can cut down on thousands of database requests per second.
Update: Proof of concept
https://github.com/msavin/userCache
To me it seems like a very interesting idea. In my app this is exactly the case. Recently needed to switch over to more fine grained roles and therefore switched from userId() to user() checks inside most methods to check for role booleans inside the user document. Seemed like rather wasteful to pound the DB for the same doc all the time with each method call, especially since in most apps the roles data will change very infrequently, if at all.
If this can be done based on existing server side caching, then perhaps the magic trifecta is in reach - (1) with not too much work get (2) potentially big performance benefits while (3) remaining backwards compatible. Caching always introduces strange quirks, but @msavin 's suggestions seems to address this well - having the default option be a call to the DB, as it is now, and users needing to opt in to caching.
Woot - setting up the POC was way easier than I expected, and given the package's tiny size, I think it should work just fine.
Having played with it some more - I think this can be fine as a third party package, and I would be happy to maintain it and promote it.
@vooteles thanks for the positive words. It would be great to see if you can implement Meteor.userCache into a few method calls and see how it works. Indeed - it sounds like this can help you cut down maybe even on half of your database calls.
The only thing that you might need to look out for is ensuring that the data you are trying to retrieve from the cache is being pushed up to the client.
Wow. Very fast work I must say. I can try it out, but unfortunately not very quickly (and the app is not in production and not APM is set up, so there should be much better sources of data in the community). But regardless of that, would be interesting to see what the fine folks at MDG think about this. Especially since I do have a rather strong allergy towards third party packages. Yes it is only a few lines of code, but that should be exactly the reason why it could be (barring any issues that I might not be seeing here) a good candidate for Meteor's core.
New version is up - it now monkey-patches the Meteor.user field and provides some new options.
There's also a new discussion on the forums: https://forums.meteor.com/t/introducing-meteor-usercache-the-one-simple-trick-that-can-save-you-millions-of-database-requests/45336/6
I agree, a PR to OEM would be more acceptable.
Shying away from 3rd party libs these days.
Are you sure mergebox is the best place for this? Why not observe demultiplexer's _cache which also contains documents?
@mitar I've not come across it. Can you make a sample of how it might work?