I have a webpage with a button that generates some files to a server path. (It takes somewhere from 5 to 20 minutes). I want to create an async task that will continue executing even after the user closes the browser. Is it possible to do this with asp.net 4 and C#?
You do not control the thread pool in an asp.net application. You cannot even guarantee that a request will be completed on the same thread that it started with. Creating threads uses the same application pool that the web server uses, and you can use up all the request threads leaving your web server unavailable to process requests.
You should implement a windows service that hosts a WCF service that you can call from within your web application. In the service you can then fire off a thread to process the long running process. At the end of that process you can then update a status flag (e.g from Processing to Complete) that the user can view to determine if the files are done processing.
I would recommend using Topshelf to implement your windows service, it will save you much headache.
Actually, it is recommended that you not do this. Instead, the recommended way is to create a service (e.g. a windows service) that performs your processing asynchronously. In your web application, you create methods that starts the process, and another method that polls the service to determine if processing has completed.
There are a number of reasons for this, but one of the biggest is that the default and recommended configuration for webservers allows the server to kill long-running requests.
Or that I didn't understand what you want to do, or that you don't need to do a thing.
After the request was sent, the request process continues no matter if the user browser was closed or not. You don't need to do a thing
Fabulous nature of stateless WEB applications...
Creating new thread / using thread pool is the easiest approach to create run away tasks.
Note that there is no guarantees that process will stay alive for duration of a long task - so be prepared to handle partial completion and manual restarts. I.e. AppPoll recycle due to config change.
Easiest way is to put your task on the ThreadPool. The thread pool threads will stay alive even after the web page has completed rendering. The code would look like the following:
/* Beginning Method */
object someData = new object();
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessAsync), someData);
/* Ending Method */
static void ProcessAsync(Object stateInfo)
{
string dataToString = stateInfo.ToString();
}
you have to create a thread that does the long running task
have a look at the below:
http://kiranpatils.wordpress.com/2010/01/01/performing-a-long-running-task-with-asp-net/
Anyway what ever you start on the server it will continue running even if the user close the browser(until you recycle the app-pool or restart the web server).
Related
I'm maintaining an ASP.NET Core web application that needs to repeatedly run some background threads. I know it's not a good design but currently I have to fix its major issues with minimum effort. Now I wonder if I should worry about handling users http requests by web server or not?
Question is simple but I can't find any clear answer for it:
What is the difference between threads that are created in application like this:
Task.Run(() => { // some parallel job })
and worker threads of IIS that handle http requests?
Are they come from the same thread pool or they're reside in separate pools?
According to this it's all one pool: "ASP.NET Core already runs app code on normal Thread Pool threads." In other words, there isn't a separate max for threads serving requests vs. background threads.
The biggest difference is that IIS is aware of the threads it creates itself for an incoming request. IIS is not aware of any threads you create yourself.
When an app pool is recycled, or IIS is shut down, it waits until all requests have finished processing - it waits until the threads it creates for each request has finished processing - and then it kills the process. If you create any threads that outlive the request (for example, if you create a background thread and then send the response back to the client) IIS has no idea that thread is still running and could kill the whole process at any time.
If you don't return a response until all the threads are complete, then you won't have that specific problem.
The other issue is that you may hit the maximum number of allowable threads. Then all kinds of weird performance issues would happen. But that depends on how many threads you are creating and how many HTTP requests are coming in.
I have a .NET MVC web app for data reporting. When the app first loads, it requests a lot of data from remote servers then caches it locally in web server memory. Before the cache loads, there's no way to respond to incoming requests. Every request that comes in while the cache is loading must wait for the thread loading the cache.
If I use a critical section (lock) on the caching code, all the requests will block. That's a huge waste of resources and I could even exhaust my IIS worker thread pool.
If I use async requests, the web requests will all return before the cache is loaded. I can't "callback" a web request which has already returned its contents to the client!
How can I manage the threads properly? Maybe there a way to move all requests to a single thread which asynchronously waits for the cache to load and then move them back out to individual threads once the cache is loaded?
If I use a critical section (lock) on the caching code, all the requests will block.
That is true. You can use SemaphoreSlim.WaitAsync to asynchronously wait. This behaves like a lock. You probably want a solution for the case that many requests queue up (like 1000s). You can use a second semaphore for that with a max count of 1000 and a wait timeout of zero. If the wait fails you know that >= 1000 requests are running and you can fail the request.
Big downside is that now all your requests have some async component to it. Maybe you can do this in some central place such as an async MVC action filter. Otherwise you will be forced to make all MVC actions async which is a headache.
Be sure to correctly configure all ASP.NET and IIS queues.
If I use async requests
Not sure you understand what async means in the context of ASP.NET. Async request processing is an implementation detail of the server. The client can't detect it. The request is not prematurely completed. Async IO (and any other form of async blocking) does not cause the request to end prematurely.
Don't put the Loading of the cache in a new thread: If you want that no requests are served you should load the cache in app_start. If the application loaded reuqests are served again.
Does the app require restarting often? If not, you can have some type of a fetch routine that requests updated data from remote web servers, and swap out all relevant caches in one critical section.
In essence, fetch the data in the background and commit all at once (you can lock during the commit to avoid contention over proper values).
We have an IIS-hosted WCF service that receives a large chunk of data to work on. The service fires up several worker threads and then returns leaving the worker threads to finish the job (which might take an hour). If the WCF service is idle long enough IIS recycles tha app pool aborting the worker threads. This problem has been circumvented by having the worker threads occasionally call a dummy service just to keep the app pool alive. If you think this whole setup is a really bad idea, I completely agree (not my code). So no need to comment that.
The problem is we still get an occasional ThreadAbortException. Is there any way to get additional information about what/who initiated the thread abort? I know it isn't our code.
IIS logs turned out to give the answer. AFAIK, if new binariers are loaded IIS waits until all service calls are finished (and no new call are accepted), then recycles the app pool. However, IIs has no knowledge of the background threads running after the service and therefore thinks it's free recycle the app pool. In some cases we've been uploading a new version while the background threads are still running. In any case, a very bad architecture.
I have a application that will allow a user to upload a file. After the upload is complete there are a number of processing steps that must be done on the server (decompression, storage, validation, etc ...) thus the user will be informed sometime later by email when everything is complete.
I have seen a number of examples where the BackGroundWorker from System.ComponentModel is used to allow asynchronous work to be done in another thread. However, it seems like they lead to the user eventually getting a response. In our case no web response is necessary - the code can take up to 30 minutes to complete.
Is there another way to start a completely separate thread/process that will keep running even after the user completely closes their session?
If there is no need to respond immediately, you want to offload to some other process to do the heavy lifting. I would dump it in a DB, folder or post to a Message Queue. The worker processes (Windows Services?) would process the files, reading from the db, file system or queue. When the work is done, your worker process can call out to your ASP app (webhook style) if it needs to know when it's done. Just a suggestion.
Write a Windows Service that will run on the ASP.NET server. Architect it in such a way that it can accept and queue job requests. The queue will allow you to create the optimal number of threads in a ThreadPool for executing a subset of the queued jobs concurrently. Submit jobs to the Windows Service using either .NET Remoting, or WCF.
If processing can take up to 30 minutes, I'd recommend skipping using a background thread from the the web worker process and using something like a Windows service instead, or running a console application on a schedule using the Windows scheduler.
Once the file is uploaded, you would add it to a queue of some sort (either in a database, or using a message queuing system like RabbitMQ if you're feeling adventurous). Your web request could then return immediately and let the user know that the file is being processed, and the background service would pick the item up off the queue and continue the processing, emailing the user when it is complete.
I am getting into windows services and looking over some tutorials, but they are all very dumbed down. They usually involve printing something out in the overridden OnStart method. That sounds like it gets called once. Now where would I put code that needs to be run continuously?
All of the On... methods in your service class should return as quickly as possible. They will end up being called whenever the Windows service controller interacts with your service, and the service controller will be waiting for a successful return. Whenever you use the Services Control Panel applet and you start or stop a service, that progress bar you see is what is shown while waiting for that service's equivalent of OnStart or OnStop to return.
So the typical thing to do in OnStart is one or more of the following:
start a separate thread that performs the constant task your service will perform
set up a timer (of the System.Threading.Timer variety) that will periodically perform whatever action your service does periodically (perhaps polling for some state)
start listening asynchronously on a network port, perhaps with a TcpListener or UdpClient
subscribe to some system event
In any of these cases, your service's task is performed asynchronously, and you exit from OnStart immediately. But remember to keep track of your thread, timer, TcpListener, or whatever, so that you can interact with it in OnStop (and optionally OnPause and OnContinue). Usually the thing to do is to dispose of any timers (so they won't fire any more), shut down any sockets or listeners, then set a ManualResetEvent. Any threads you have running should check this event periodically and exit once it's signaled. If you want to ensure a successful shutdown of the service and risk possible data loss, you might join to any running threads with a reasonable timeout (30 seconds is common), then abort any threads that are still running after the timeout has expired.
The same as any other project that has more than a couple of classes - you put it in a separate project.
The 'Windows Service' project should just contain the boilerplate stuff to start the service, any timers that are part of the service, and that sort of thing. Putting the rest in another project allows you to use your business logic in a desktop app, a web app, as a WCF service and so on later on.
To create any Windows Services the proper way, I stick to TopShelf library. It is IoC friendly and you can keep the Windows Service infrastructural code completly separate from the logic of the service. You also can run the service as a console application and just convert it to a windows service on production. I think it is "THE" way to create Windows Services and never looked back.