I have a web method in an ASP.NET site that could run long and consume a lot of CPU capacity. It is also possible that, before a request is returned, the user could fire a new request with other or more parameters from the site. On the client side a do an abort:
if (xhrConfigurate != null) {
xhrConfigurate.abort();
}
Of course, abort will not stop the calculations on the server. I tought, this is ok, the server will do what it have to do, but will not return the results of the old requests. But it seems that in some cases, the server has troubles to handle all requests in a timely matter.
That is why I also want to kill the old requests when a user launches a new one. I have found some solutions with scriptmanager, but would like to avoid using that.
As the webmethod itself is a asynchronous thread, can't I get an instance of this thread, store it in some dictionary where I can abort the old not finished requests for a user and remove a request when it is finished?
<WebMethod> Public Shared Function myRequest(ByVal params As String) As String
'Get the dictionary with requests
'Test the dictionary on old unfinsihed request for the user, if there is one: abort
'Add this request to the dictionary
'Do work...
'If work finsihed: remove this request from dictionary
Return result
End Sub
If I understand correctly, you want to have some global variable dictionary with requests queue, so that any web method execution would share same dictionary?
Using global variable is tricky thing, IIS application pool may restart anytime. Somewhere I read, it's recycling automatically every 24 or 29 hours on IIS. So global variable values might be lost.
Thread related to the problem:
What exactly is Appdomain recycling
I have ASP WebApi service, and I have similar long running tasks. I host ASP application in console app (host) (no IIS!), and I use ObservableCollection variable to store requests in AppDomain.
Then each requests thread can access that collection safely (if I am not mistaken).
In general, it is a bad idea to run a long-running process inside of ASP.NET. Instead, you should create a separate server process, and your ASP.NET code should queue a request to that process.
Your server could return a unique value back to ASP.NET, which could then send that value back to the web page. When the user makes a request, you would pass that value to ASP.NET, which would pass it to the service. The service could determine whether there is already a request running with that unique value and, if there is, the service could abort that thread.
Related
For logging purposes of an ASP.NET web application, I keep some state information in a static class. These fields are marked [ThreadStatic] so every thread has its own copy of the field. The logging methods are called from the HttpApplication event methods:
Application_BeginRequest (request start, initialise state)
Application_AcquireRequestState (session and user are known)
Application_EndRequest (request end, clean up)
I can now observe that, under certain circumstances, a page request is processed in different threads. The BeginRequest event runs on thread 18 while the following events run on thread 4. Of course my thread-static data is then not available and an error occurs.
Most of the time this works just fine and every request is processed in a single thread only. But when I request a page that loads ~5 seconds and after 1-2 seconds click on another link, both requests run in parallel. The first is completed on thread 24 (where it was also started) after 5 seconds, while the other starts on thread 18, but after the first request has completed, the second continues to run on thread 4.
Trying it with 3 overlapping long requests, it's a pure chaos. I can even watch two requests starting on the same thread while they later continue on different threads each. There doesn't seem to be any relationship between a request and a thread.
How can it be that a request is changing threads? It's losing all of its state if it decides to move on to another thread. And every description I can find says that it all happens in a single thread.
ASP.NET 4.0 on IIS 7, Windows Server 2008 R2, x64.
Alternative: If I cannot rely on requests being processed in only a single thread from the start to the end, then what would be the best location to store small amounts of per-request data (currently an integer and a class) that is very fast accessibly? And preferably also works without a reference to System.Web (my code is targeting the client profile as well). I know about HttpContext.Current.Items[key] but it's looked up somewhere deep in the remoting assembly and involves a dictionary which seems a lot slower than a thread-static field.
ASP.NET is thread agile and a request can be processed on more than one thread (but not more than one at time). Because of this you really can't use ThreadStatics in ASP.NET. However, you can safely use the HttpContext.Items dictionary to store things which need to be scoped to a single request.
To allow your code to work outside the context of an ASP.NET application, you could create a wrapper that swaps HttpContext / CallContext, depending on which environment the code is in. Here is an example of such a wrapper.
I have the need to have an option to enabled deep debug logging using log4net. I am familiar with how classic ASP.Net handles threads, but I wondered how threads work with ServiceStack. The goal would be to use %Thread to group requests together in the log. I think the only problem is that there is likely a thread pool and the %thread id will be reused on subsequent requests.
Really what I am looking for is a single unique id I can expose to log4net so I can group the entire logging of a single request together when building a report.
Can anyone lend some guidance?
See this page on concurrency in ServiceStack, i.e. ServiceStack when hosted in ASP.NET doesn't create any new threads itself, requests are simply handled on the same IIS/Nginx/etc ASP.NET HTTP WebWorker that handles the request. Ultimately control of the Thread Pool and thread instances is up to the underlying ASP.NET but its common for them to re-use the same threads to handle different requests.
Use IHttpRequest.Items whenever you want to share any data throughout the lifetime of a single request, e.g. you could simply assign a Guid at the start of the request using a PreRequestFilters with:
this.PreRequestFilters.Add((req, res) => req.Items["ReqId"] => Guid.NewGuid());
Which lasts the entire lifetime of the request and the same instance of IHttpRequest is available in all filters, services, views, etc.
How does IIS handles multiple simultaneous requests to a web service using the same session id when that web service relies on sessions?
If the first web service call has not finished processing, does IIS queue the second web service call temporarily until the first web service call has finished (since they both rely on the same session data).
Or does IIS allow both requests to go forward and any changes made to the session store by the first request immediately affect the second web service call in process even thought that may cause unexpected results.
I believe it is using the first option by queuing the second call until the first is completed due to session reader\writer locks but I have not been able to locate a definitive answer.
Note: In this case the web service requests are generated from the client browser asynchronously.
Yes, like anything else that's using session state, the session state module is going to block the request from going any further down the pipeline (i.e. executing your ASMX web method) until it can aquire the lock to the session. Session state is the enemy of concurrency, avoid it at all costs.
I have created a ASMX Web Service which does some Active Directory stuff behind the scene.
As I wish to retain certain information within Web Services under user session, I have decided to put [WebMethod(EnableSession = true)] and start using Session variables.
However, when I turn that option on, the return time from app -> web service -> app has became ridiculously long. (about a minute or more).
If I remove [WebMethod(EnableSession = true)], it is fairly fast.
Anyone know what is going on?
Possible reasons:
Session state is stored out of process (state server/ SQL server) and getting/storing it taking a long time
You are making multiple concurrent requests (including service requests) under the same session. ASP.NET ensures that only one session-full (session read/write) request execute at a time and hence, multiple concurrent requests would queue up.
EDIT :
For #2, obvious solution is to avoid session state use - for example, can you put the relevant information into another store such as cache or database (expensive).
If you are only reading session state in web service then you may take advantage of read-only session state (see IReadOnlySessionState). Read-only session state allows concurrent read-only requests - read/write request will still block all other requests. Now, EnableSession from WebMethod attribute does not support this - it either provides no session or read/write session. So one of the workaround can be to implement your own handler implementing IReadOnlySessionState and then route asmx request to thi handler using a http-module and then switch the handler to default one later. Because your handler requires read-only session state, you will have the read-only session state - see this forum post where such http-module that switches the handler has been given.
I have some doubt over HttpModule and HttpHandler Please help me to clarify
1)In HttpModule I have noticed methods Init called only once . context_BeginRequest and context_EndRequest etc method calling for each request.
Is it guaranteed that for a module Init will call once for different users(or different request) and BeginRequest etc will call every time for different users (or different request) ?
2)Is there any possibility that Application_Start(global.asax) can run more than once because there may be more than one application object
3) Since application object can be different (from application pool) In this case how Application data is shared between different users?
4) In HttpHandler ProcessRequest method will call for each request (or for each user).
Thanks
Ritu
"Is it guaranteed that for a module Init will call once for different users(or different request) and BeginRequest etc will call every time for different users (or different request)?"
The init method will be called when the app pool starts / when the application is started for the first time. This is when the module is loaded.
The BeginRequest method is called every time the application starts handling a new HTTP request.
"2)Is there any possibility that Application_Start(global.asax) can run more than once because there may be more than one application object"
There is not more than one application in a particular folder. IIS doesn't work that way. Only one global.asax per application, and Application_Start will only be called once for each application unless the app pool is reset.
"3) Since application object can be different (from application pool) In this case how Application data is shared between different users?"
Depends where you're storing this application data and what you're using to retrieve it. I'm not sure what you mean about this. Session data should be scoped to an individual application (certainly for in-process session state server, and if properly configured also for out-of-process session state server)
"4) In HttpHandler ProcessRequest method will call for each request (or for each user)."
Yes, but only for requests which are mapped to your handler. Conversely, HttpModule can be called for ALL requests.