This is easier to explain if I first explain my order of events:
User requests a webpage that requires x database objects
The server checks the cache to see if it is cached, and if it is not, it re-requests the database
The page is sent to the user
My issue is, when the user requests a webpage and the cache is expired, it will take a very long time for the cache to update. The reason is because the data that is being cached includes data fetched from other locations, so web requests are being made to update the cache. Because it is making web requests, it can take quite a while for the cache to update, causing the user's webpage to sit there and load for upwards of ten seconds or more.
My question is, how would I go about reducing or completely removing these edge cases where, when the cache is updating, the user's webpage takes forever to load?
The first solution I came up with was to see if I could persist the MemoryCache past its expiration time, or at the very least check its expiration time, so that I can fetch the old object and return that to the user, and then initiate a cache update in another thread for the next user. However, I found that MemoryCache completely removes the items entirely upon expiration (which makes sense), and that there is no way to avoid doing this. I looked into using CacheItemPriority.NeverRemove, but there is no way to check the expiration time (for some weird reason).
So the second solution I came up with was to create my own cache, but I don't know how I would go about doing that. The object I am storing is a list objects, so I would prefer to avoid a wrapper object around them (but, if that's what I have to do, I'll be willing to do that). I would like this cache to be abstract, of course, so it can handle any type of item, and using a wrapper object for lists would not allow me to do that.
So what I'm looking for in a custom cache is:
Ability to check expiration date
Items are not removed upon expiration so that I can manually update them
Yet through the past couple of hours searching online, I have found nothing that describes a cache that's even remotely close to being able to do something like this (at least, one that's provided with .NET Core or available in the NuGet packages). I have also not found a guide or any examples that would help me understand how to create a custom cache like this.
How would I go abouts making this custom cache? Or is a cache even what I'm looking for here?
Related
I have a web-service which is called by some web-service clients. This web-service returns the current inventory list of an inventory. This list can be big, 10K+ of product IDs, and it takes quite some time (~4 minutes) to refresh the list by reading data in the database. I don't want to refresh the list every time this web-service is called, as it may consume too much resource on my database server, and the performance is always not very good.
What I intend to do is giving the inventory list some time-to-live value, which means when a client asks for the inventory list, if the data is not out-of-date I just return the data right away; if the data is obsolete I will read it from the database, update this list data and its time-to-live value, and then return the refreshed data back to the web-service client. As there may be several clients call this web-service, It looks like I need a multi-thread synchronization(multiple-read single-write, ReaderWriterLockSlim class?) to protect this inventory list, but I haven't found a good design to make this web-service have good performance: only one client refreshes the data, the other clients don't have to redo the work if the data is still within the time-to-live frame and the web-service should return the result as soon as possible after the write thread completes the update.
I also think about another solution (also use ReaderWriterLockSlim class): creating a separate thread to refresh the inventory list periodically (write-thread refreshes the data every 15 minutes), and let all the web-service clients use read-thread to read the data. This may work, but I don't really like it as this solution still waste resource of the web-server. For example, if there is no client's request, the system still has to refresh the inventory list data every 15 minutes.
Please suggest some solution. Thanks.
I would suggest using a MemoryCache.
https://stackoverflow.com/a/22935978/34092 can be used to detect when the item expires. https://msdn.microsoft.com/en-us/library/7kxdx246.aspx is also worth a read.
At this point, the first line of the code you write (in CacheRemovedCallback) should write the value back to the MemoryCache - this will allow readers to keep reading it.
Then it should get the latest data, and then write that new data to the MemoryCache (again passing in a CacheItemPolicy to allow the callback to be called when the latest version is removed). And so on and so on...
Do you ever run only one instance of your service? Then in-memory caching is enough for you. Or use a ConcurrentDictionary if you don't want to implement the lock yourself.
If you run multiple instances of that services, it might be advisable to use a out of process cache like Redis.
Also, you could eventually maintain the cached list so that it is always in sync with what you have in the database!?
There are many different cache vendors dotnet and asp.net and asp.net core have different solutions. For distributed caching there are also many different options. Just pick whatever fits best for the framework you use.
You can also use libraries like CacheManager to help you implement what you need more easily.
A few days ago, i create my little project. This project is my personal blog. He based on ASP.NET WebAPI (back-end), Angular (front-end).
My Post entity have ViewCount field.
How to calculate the number of post views? And that at restart (F5), the counter does not increase.
Is there a ready-made piece of code or implementation tips?
Thanks to everyone who responds.
You'll need to create something on your own as your question too broad, but generally speaking, you'll need to update your Post entity in your action each time it's hit. For example:
post.ViewCount++;
db.Entry(post).State = EntityState.Modified;
db.SaveChanges();
However, there's a number of things to take into consideration:
You'll need to plan for concurrency issues (i.e., multiple simultaneous requests attempting to update the view count at the same time). To do that, you'll need to catch and respond to DbUpdateConcurrencyException when saving.
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
// handle it
}
There's various strategies for how to handle concurrency. Microsoft details your options. However, simply handling it once, may not be enough as the next save could also cause a concurrency exception, and so on. I'd recommend employing something like Polly, which gives you far more powerful exception handling abilities, including retrying a number of times or forever.
You'll need to weed out duplicate requests (From an F5 refresh, for example). To do that, you'll likely want to set something in the user's session, such as an access time, and then only count the view if it's been some determined amount of time since the user last accessed the page, or the key doesn't exist in their session (first view). Bear in mind session timeouts with this though. For example, if you only want to count a view for a user every hour, but your session times out after 20 minutes, that's not going to work. In that scenario, you'd want to store the access time some place more persistent, like a database table. If you do use the session, you should also use a SQL Server or Redis backing for your session state, rather than In Proc or State Server, since the former will be much more reliable than the latter.
You'll need to take into account bots. This could be any automated viewing of the page, benign or malicious. At the very least, you'll want to account for spiders like GoogleBot, so you don't increment the view count every time your site gets indexed. However, trying to determine if a request originates from a bot or not, is a whole thing in itself. Entire databases of bot UA strings are managed explicitly to try to track what's out in the wild. It's achievable to exclude at least a vast majority of automated traffic, but your view count will basically be as accurate as you are about filtering bots out.
Based on all that, unless you have a really good reason you actually need to track the view count yourself, I'd say don't worry about it. For example, if you're just trying to report internally on usage statistics, employing something like Google Analytics, will be a far easier and more manageable solution. Even if you do need the view count for something in your application, it still may be better to install third-party analytics software locally. Look for a solution with an API or at least some way to get at the data programmatically, and then you can simply pull the view count from that.
Net web api developer and i want to know if im working correctly.
Im saving a changeable objects into the cache.
Other developers on my team said only static data should be stored in the cache.
So i wanted to know if only static data need to be store in cache or there's another right way to do it.
Thanks.
I use caching for changeable objects because they take a reasonable amount of time to generate, although the frequency of their changing varies.
There are a couple of things which I do to try and make sure the data is always valid.
On the cached item I put a policy which will keep the item in cache for say 15 minutes, and make the expiration time sliding. This keeps the used items in cache but drops less used items.
I also have cache eviction end points on the API, and the process which updates the data in the database calls the endpoint once the process has been complete. The items which have been updated are then removed from the cache and hence rebuilt the next time they are requested.
In the end I think it all boils down to how long it takes to get the object you are trying to return, and whether the delay to generate it is acceptable.
I'm working on an intranet and I'd like to cache an object on the server and serve that up to users when requested, as opposed to having each user generate their own copy of the object. I'd also like to refresh the object every 30 minutes...
I'm currently using HttpContext.Current.Cache, but I'm unsure if:
1. that's what I'm looking for
2. there's a better way to do this (I'm thinking web service)?
Thank you.
HttpContext.Current.Cache is appDomain wide cache shared between all users. It is appropriate place for your case to store whatever objects you need to share across all users. It also supports expiration.
Using HttpRuntime.Cache (same as HttpContext.Cache) has the pitfall in that it's tied to the AppDomain. When that recycles so does your cache.
Instead install something like Membase (Memcache) which acts as an external cache provider and will be persistent between application recycles.
As to refreshing, personally I would cache the item for 30 minutes but allow it to expire. Only refresh it when a request comes in and the item is no longer in the cache. This keeps the cache efficient in that only requested objects remain in the cache.
As a shameless plug I wrote a cache library a while ago that supports Memcache which you can use, see here - http://www.lloydkinsella.net/2012/09/30/bettering-the-better-net-cache/
I was wondering if i should be caching the objects returned from my DAL in some way? I may have multiple UI controls calling for the same data in a single load of the page.
What would you guys recommend? Am i begin a little to cautious? Its not a terrible amount of data. But if i should be caching in some way, what would be the recommended approach?
You could cache AND if you really have multiple controls on the same page using the same data you can call the data once in the parent page and pass a reference to it to each control with a Setter in each control (rather than have each control pull the same data from the DAL themselves), eg:
myControl.AllUsers = _allUsers;
....
myOtherControl.AllUsers = _allUsers;
I also agree with #DanielHilgarth. Caching adds complexity (when to refresh the cache, for example). If the page loads quickly anyway, I wouldn't bother.
If the page is slow, database calls in loops are often the culprit in my experience.
It depends if it's safe and nescessary to do so. If the data you are working with does not require realtime data (ie. your blog) then by all means cache if you feel it's nescessary to do so (meaning your site is running slow).
A problem with caching that a lot of times people forget to account for is being able to clear the cache on demand if something that requires an immediate response (for example you ban a user, or update payment gateway information).
There are two main types of caching, sliding cache and fixed-time cache.
Sliding cache (cache that gets extended each time a valid retrieval is performed) is great for resources that have relatively easy to compute values, but may suffer from database / network overhead. Cache for 1 hour (or w/ever) on a sliding cache, and then manually invalidate (remove) the cache whenever an INSERT / UPDATE / DELETE occurs for the DAO. This way the user will see realtime results, but will infact be cached whenever possible.
Fixed time cache is great for resources that are difficult to perform (ie a very complex stored procedure) and do not require realtime accuracy. Cache for 1 hour (or w/ever) for the first time it's requested, and do not clear cache until that first hour is up. INSERT / UPDATE / DELETE is ignored by your cache mechanism (unless it's absolutely nescesssary).
To do so you can look at this library:
http://www.reactiveui.net/
it provides a neat an clean way to cache your objects.
I'd say it is a very neat way.