I have an ASP.NET MVC 3 / .NET Web Application, which is heavily data-driven, mainly around the concept of "Locations" (New York, California, etc).
Anyway, we have some pretty busy database queries, which get cached after they are finished.
E.g:
public ICollection<Location> FindXForX(string x)
{
var result = _cache.Get(x.ToKey()) as Locaiton; // try cache
if (result == null) {
result = _repo.Get(x.ToKey()); // call db
_cache.Add(x.ToKey(), result); // add to cache
}
return result;
}
But i don't want to the unlucky first user to be waiting for this database call.
The database call can take anywhere from 40-60 seconds, well over the default timeout for an ASP.NET request.
I want to "pre-warm" these calls for certain "popular" locations (e.g New York, California) when my app starts up, or shortly after.
I don't want to simply do this in Global asax (Application_Start), because the app will take too long to start up. (i plan to pre-cache around 15 locations, so that's a few minutes of work).
Is there any way i can fire off this logic asynchronously? Maybe a service on the side is a better option?
The only other alternative i can think of is have an admin page which has buttons for these actions. So an administrator (e.g me) can fire off these queries once the app has started up. That would be the easiest solution.
Any advice?
The quick and dirty way would be to fire-off a Task from Application_Start
But I've found that it's nice to wrap this functionality into a bit of infrastructure so that you can create an ~/Admin/CacheInfo page to let you monitor the progress, state, and exceptions that may be in the process of loading up the cache.
Look into "Always running" app setting for IIS 7.5. What this basically do is have an app pool ready whenever the existing one is to be recycled. Of course, the very first would take the 40-60 seconds but afterwards things would be fast unless you physically restart the machine.
Before you start cache warming, I suggest you check that the query is "as fast as it can be" by first looking at how many logical reads it is doing.
Sounds like you should just dump the results in a separate table and have a scheduled task to repopulate that table periodically.
If one pre-calculated table isn't enough because it ends up with too much data that you need to search through, you could use more than one.
One solution is to launch a worker thread in your Application_Start method that does the pre-warming in the background. If you do it right, your app won't take longer to start up, because the thread will be executed asynchronously.
One option is to use a website health monitoring service. It can be used to both check website health, and if scheduled frequently enough, to invoke your common URLs.
Doing the loading in a Task from Application_Start is the way to go, as mentioned by Scott.
Just be careful - if your site restarts and 10 people try to view California, you don't want to end up with 10 instances of _repo.Get(x.ToKey()); // call db simultaneously trying to load the same data.
It might be a good idea to store a boolean value "IsPreloading" in the application state. Set it to true at the start of your preload function and false at the end. If the value is set, make sure you don't load any of your 15 preloaded locations in FindXForX.
Would suggest taking a look at auto-starting your app, especially if you are load balanced.
Related
On a new website, I've an huge formular(meaning really big, needs at least 15-20min to finish it), that configure the whole website for one client for the next year.
It's distributed between several tabs(it's a wizard). Every time we go to the next tab, it makes a regular(non ajax) call to the server that generate the next "page". The previous informations are stored in the session(an object with a custom binder).
Everything was working fine until we test it today with all real data. Real data needs reflexion, work to find correct elements, ... And it takes times.
The problem we got is that the View receive a Model partialy empty. The session duration is set to 1440 minutes(and in IIS too). For now what I know is that I get a NullException the first time I try to access the Model into my view.
I'm checking the controller since something like 1 hour, but it's just impossible it gives a null model. If I put all those data very fast, I don't have any problem(but it's random data).
For now I did only manage to reproduce this problem on the IIS server, and I'm checking elmah logs to debug it, so it's not so easy to reproduce it.
Have you just any idea about how should I debug this? I'm a little lost here
I think you should assume session does not offer reliable persistence. I am not sure about details but I guess it will start freeing some elements when it exceeds its memory limit.
You will be safer if you use database to store that information or you could introduce your own implementation for persisting state.
in addition to ans provided by #Ufuk
you can easily send an ajax request every 1 minute which would actually do nothing but by doing this the session wont get expired and site will continue to run in extended periods
The problem was that the sessions wasn't having enough space I think. I resolved temporary my problem by restarting the application pool. Still searching a solution that will not implies to changes all this code. Maybe with other mode of session states, but I need to make my models serializable.
I would like to create a background task which continuously inputs the location from a mobile to a database and in a website, I would like to get the same location immediately as it changes.
I am using an SQL Azure database. so pushing and polling are not an option. Also I am not sure if I can use a cache since the location continuously changes.
I think I have to create some infinite loop which carries on a task continuously. But how does this concept work?
Does this simply involve the create of a thread and a while(true) { ... } ?
I worked on a similar situation, and the approach I went for was to have an special page (/StartJob.aspx?AccessKey=xxxxxxxxxxxxx), that when hit with the right access key, would start a job cycle.
I then setup a "Cron Job" using www.setCronJob.com, to call this page at regular intervals. This service can notify you by email if it fails too.
Have a look at the timer control
http://msdn.microsoft.com/en-us/library/bb386404.aspx
sounds like something that could help out with achieving what you need :)
I am using master page in which menu is generating dynamically according to user role in code. The same menu is used for all application to a particular user up to log out. So instead of recreating it, i need the same menu for all of the application. The Menu is in StringBuilder which is very large size. Is Session or Data cache is better and less memory consuming in my situation and why. Please suggest?
I want to improve performance of master page.
Thanks
I think Cache will be better as you will have only one instance created for one role, but Session will make it create multiple instance as many as user is accessing, and you will have to wait session timeout sometimes to free the memory
If every user will get the same menu:
You should consider putting it in the Application "Cache" - Application["MyMenu"] or a static field on one of your objects.
The main reason for this is lifetime. If you put it in an application level object, then it will last for the lifetime of the application. Putting it in a session level object will cause it to be lost when that session ends - as a session is started per user, then you will soon find yourself recaching the data.
On the other hand... if it's unique per user:
The session provides a handy place to put this data, as it is unique to that user, and will not live long beyond that user leaving the site.
Also think about:
If you really think memory is going to be an issue or you want to define exactly how long you keep it for
Put it in the Cache. You can determine the amount of time it lives in the cache, and, additionally, the cache will start to dump objects when it gets short on memory - so it is more sensitive to load than the other options.
There is a good discussion of Session vs Cache on SO already
Additionally
Are you sure your menu is that big? If it is, you might want to consider alternatives - just how big are you talking?
Given the chart here, what should I be looking at to identify the bottleneck? As you can see, requests are averaging nearly 14 seconds under load and the bulk of that time is attributed to the CLR in New Relic's profiling data. In the performance breakdown for a particular page, it attributes the bulk of the time to the WebTransaction/.aspx page.
I see that the database is readed also (the orange) and this is seams that one of all pages have delay the rest of pages because of the lock that session make on the pages.
you can read also :
Replacing ASP.Net's session entirely
My suggestion is totally remove the session calls and if this is not possible, find an other way to save them somewhere in database by your self.
Actually in my pages I have made all three possible options. 1. I call the page with out session. 2 I have made totally custom session that are values connected to the user cookie, and last 3. I have made threads that are run away from the session and they make calculations on background, when they finish I show the results.
In some cases the calculations are done on iframe that call a page without session and there later I show the results.
In the Pro version, you can use Transaction Traces, which help pinpoint exactly where the issue is happening.
ASP.Net session appear perfect for a traditional WebForms app, but they do some things that are a serious problem for a modern AJAX and MVC application.
Specifically there are only 3 ways to access the ASP.Net provider:
Locking read & write (default) - the session is locked from AcquireRequestState firing until ReleaseRequestState fires. If 3 requests occur from the browser at once they'll queue up on the server. This is the only option in MVC 2, but MVC 3 allows...
Non-locking read only - the session isn't locked, but can't be saved to. This appears to be unreliable though, as some reads appear to lock the session again.
Session disabled - any attempt to read or write to the session throws an exception.
However with a modern MVC app I have lots of AJAX events happening at once - I don't want them the queue on the server but I do want them to be able to write to the session.
What I want is a fourth mode: Dirty read, last write wins
I think (happy to be corrected) that the only way to do this is to completely replace ASP.Net's sessions. I can write my own provider, but ASP will still call it with one of the 3 patters it supports. Is there any way to make ASP.Net support optimistic concurrency?
This leaves me replacing all calls to the session with a new class that basically does the same thing, but doesn't lock - which is a pain.
I want to keep as much of the current session stuff as I can (most significantly session IDs in various logs) with the minimum amount of code replacement. Is there any way to do this? Ideally I'd want HttpContext.Current.Session to point to my new class but without ASP.Net locking any requests.
Has anyone already done something like this? It seems odd that with all the AJAXey MVC apps out there this is a new problem with ASP.
First of all I say that MS asp.net have lock in the core of "asp.net processing a page" the session, somewhere in the "webengine4.dll" dll for asp.net 4
And I say that from the view point of MS asp.net act correct and lock the session this way because asp.net can not know what type of information we keep on session so can make a correct "last write wins".
Also correct is lock for the session the full page because that way is gives your a very important synchronizations of your program, that from experience now I say you need it for most of your actions. After I have replace the ms session with mine, on all of my actions I need to make global lock, or else I have problems with double inserts, double actions, etc.
I give an example of the issue that I recognize here. Session data are saved on SessionSateItemCollection that is a list of keys. When session reads or write this collection is do it all of them together. So let see this case.
we have tree variables on session, "VAR1", "VAR2", "VAR3"
Page 1.
getsession (actually get all data and place them on list)
session[VAR1] = "data1";
savesession()
result is VAR1=data1, VAR2=(last data of var2), VAR3=(last data of var3)
Page 2.
getsession (actually get all data and place them on list)
session[VAR2] = "data2";
savesession()
result is VAR1=(last data of var1), VAR2=data2, VAR3=(last data of var3)
Page 3.
getsession (actually get all data and place them on list)
session[VAR3] = "data3";
savesession()
result is VAR1=(last data of var1), VAR2=(last data of var2) VAR3="data3"
Note here that each page have a clone of the data, as he read them from the session medium (eg as they last readed from database)
If we let this 3 pages run with out locking, we do not have actually dirty read, nether "last write wins" - What we have here is "the last write destroy the others", because if you think it again, when VAR1 change, why the VAR2 and VAR3 stay the same ? what if you have change VAR2 somewhere else.
and for that reason we can not let this with out lock as it is.
And now imaging that with 20 variables... totally mess.
Possible solutions
Because of the multithread of asp.net of many pools, the only way to keep the same data across pools, and across computers is to have a common database, or a common to all process program like the asp.net State Service.
I select to have a common database as more easy than create a program for that propose.
Now if we connect a cookie that we make, to the user to the data user of the session, and we control the data using a totally custom database field that we know what we like to lock, what not, how to save or change, or compare and keep the last write wins data, we can make this work, and totally disable the asp.net session that is a generic session keeper made for all needs, but not made to handle special cases like this one.
Can asp.net make this work on the future release, yes he can by making an extra field called dirty, and on the session save data, make a merge of data using the dirty field, or something like that, but can not make this now work as it is - at least from what I have found until now.
Actually SessionStateItem have a dirty flag on properties, but did not make this merge on the end of save data. I will really love if some one else think for a solution to the existing ms asp.net session state keeper, I am write what I have found up to now, but this is not mean that for sure there is no way - I have not found it as it is.
Hope that all helps :)
Custom SessionStateModule
in this answer https://stackoverflow.com/a/3660837/159270 the James after write a custom module says: I still can't believe the custom implementation of ASP.Net Session locks the session for the whole request.