Here is what I do in a controller action:
create and start a new Thread that does a relatively long processing task (~30 seconds on average, but might be several minutes)
immediately return the page response so the user knows processing has started (trivially, a Json with a task ID for polling purposes).
At some random point, ThreadAbortException is thrown, so the async task does not complete. The exception is not thrown every time, it just happens randomly roughly 25% of the times.
Points to note:
I'm not calling Response.End or Response.Redirect - there isn't even a request running when the exception is thrown
I tried using ThreadPool and I got the same behavior
I know running threads in ASP.NET has several caveats but I don't care right now
Any suggestion?
The problem is you shouldn't do it this way. If you need a task to run for a long period of time in the background ASP.Net should either spawn a process to handle it or add the work item to a queue for a Windows Service to handle.
Does this help since you want to fire and forget.
"Delegates provide a method called BeginInvoke that allows us to call the delegate asychronously."
http://hackingon.net/post/Asynchronous-fire-and-forget-method-calls-in-NET.aspx
How about using an Asynchronous controller?
The problem was that the app was being recycled. I perfectly know that when that happens, all threads are aborted, I didn't expect the application to recycle. The reason is that the async process used changed temp files stored in the app root, and that caused a recycle.
I feel dumb.
Related
I use ASP.Net MVC 5 and I have a long running action which have to poll webservices, process data and store them in database.
For that I want to use TPL library to start the task async.
But I wonder how to do 3 things :
I want to report progress of this task. For this I think about SignalR
I want to be able to left the page where I start this task from and be able to report the progression across the website (from a panel on the left but this is ok)
And I want to be able to cancel this task globally (from my panel on the left)
I know quite a few about all of technologies involved. But I'm not sure about the best way to achieve this.
Is someone can help me about the best solution ?
The fact that you want to run long running work while the user can navigate away from the page that initiates the work means that you need to run this work "in the background". It cannot be performed as part of a regular HTTP request because the user might cancel his request at any time by navigating away or closing the browser. In fact this seems to be a key scenario for you.
Background work in ASP.NET is dangerous. You can certainly pull it off but it is not easy to get right. Also, worker processes can exit for many reasons (app pool recycle, deployment, machine reboot, machine failure, Stack Overflow or OOM exception on an unrelated thread). So make sure your long-running work tolerates being aborted mid-way. You can reduce the likelyhood that this happens but never exclude the possibility.
You can make your code safe in the face of arbitrary termination by wrapping all work in a transaction. This of course only works if you don't cause non-transacted side-effects like web-service calls that change state. It is not possible to give a general answer here because achieving safety in the presence of arbitrary termination depends highly on the concrete work to be done.
Here's a possible architecture that I have used in the past:
When a job comes in you write all necessary input data to a database table and report success to the client.
You need a way to start a worker to work on that job. You could start a task immediately for that. You also need a periodic check that looks for unstarted work in case the app exits after having added the work item but before starting a task for it. Have the Windows task scheduler call a secret URL in your app once per minute that does this.
When you start working on a job you mark that job as running so that it is not accidentally picked up a second time. Work on that job, write the results and mark it as done. All in a single transaction. When your process happens to exit mid-way the database will reset all data involved.
Write job progress to a separate table row on a separate connection and separate transaction. The browser can poll the server for progress information. You could also use SignalR but I don't have experience with that and I expect it would be hard to get it to resume progress reporting in the presence of arbitrary termination.
Cancellation would be done by setting a cancel flag in the progress information row. The app needs to poll that flag.
Maybe you can make use of message queueing for job processing but I'm always wary to use it. To process a message in a transacted way you need MSDTC which is unsupported with many high-availability solutions for SQL Server.
You might think that this architecture is not very sophisticated. It makes use of polling for lots of things. Polling is a primitive technique but it works quite well. It is reliable and well-understood. It has a simple concurrency model.
If you can assume that your application never exits at inopportune times the architecture would be much simpler. But this cannot be assumed. You cannot assume that there will be no deployments during work hours and that there will be no bugs leading to crashes.
Even if using http worker is a bad thing to run long task I have made a small example of how to manage it with SignalR :
Inside this example you can :
Start a task
See task progression
Cancel task
It's based on :
twitter bootstrap
knockoutjs
signalR
C# 5.0 async/await with CancelToken and IProgress
You can find the source of this example here :
https://github.com/dragouf/SignalR.Progress
I got the following problem, I want to execute a block of code that might take a while.
It would be a bad user experience if the user has to wait for it to finish. So I though of using a thread.
[HttpPost]
public ActionResult methode(Model model){
Task.Factory.StartNew(() =>
{
// Do a block of code that takes a while
});
return Json(new
{
succes = GetValue()
});
}
When debugging you can clearly see that the thread is being executed and that the return code is reached.
Problem I got here is that the actual return takes place when the thread is done. ( so I am not gaining any speed here.)
Why is that? And how do I make it work?
Thanks in advance!
The way you have done it above won't work because as you have observed, you have await the task and then return, so effectively it's a synchronous operation from the user's point of view and they are stuck waiting for the server to respond with the actual results of the work.
There are a couple of ways to do this though, it depends on what the nature of the task is. If this is something that generates data that the user might want to come back to later on and download e.g a report that can take a while to generate:
Using an asynchronous controller, kick off the task and keep a record on the server side via some unique identifier, and then return immediately with that identifier.
A client-side script is then triggered to poll every N seconds via an Ajax call, to see if the work is complete on the server side
However if the app pool gets recycled in IIS during the running of this thread, the work is lost and you haven't really got a way to control this
Better yet kick off the long running task in a separate process and then the client can poll every few seconds(or use SignalR from the server side to push) for when the job is done.
A typical way to achieve this is to push a record of the work to be done into a Queue and then return some kind of identifier to the client.
Your separate process can just be running all the time and monitoring the queue for new work to do, it can then update a database or cache with the results of the work.
Meanwhile the client is polling (or SignalR is pushing whereby your signalr hub checks every few seconds and pushes the job status back to the client) to see if that particular "job" is completed.
This way you are not at the mercy of the web server process going down and trashing all your threads, plus you gain much better control over cases where you need to defer jobs, spread the load over multiple servers, etc.
If on the other hand this is data that just takes a while to calculate but is only going to be available to the user on-screen, and you don't allow the user to leave the current page whilst waiting for the results, then just use a properly asynchronous Ajax call from the client-side!
I am developing a WPF application with C# 4.0 where some user-specific code will
be compiled at runtime and then executed inside an AppDomain. The process might take 10 ms or 5 minutes. The AppDomain will be created by Task.Factory.StartNew(). Works fine.
Now I want to be able to cancel/interrupt the execution. I can press a
Stop button while the codes is executing but how can I cancel the Task? I know:
there is the CancellationToken.IsCancellationRequested property but I cannot
loop through something. This is why I cannot check the value while executing
the (atomic) code. And unloading the AppDomain does not stop the Task.
FYI: I took the Task class because it easy to use. If Thread would be useful: No problem.
Can someone help me? A short code snippet would be nice :).
Thank you.
Aborting a thread or a task is a code smell of a badly designed solution.
If that is your decision, you should consider that every line of code could be the last one to be executed and consider releasing any unmanaged resource, lock, etc that could leave the system in an inconsistent state. In theory we should always be this careful, but in practice this doesn't hold.
If you try with a Thread and the inviting .Abort() method, you should consider that ThreadAbortException is a special exception in terms of try-catch and finally blocks. Additionally, you can't even be sure that the thread is going to be aborted.
In regards of using a Task, AFAIK (I'm not an expert in TPL) I'm afraid you cannot do what you want. You should somehow re-design your logic to consider the cancellation token and cleanly stop your computation.
I am creating a user defined thread library. I use Round-Robin scheduling algorithm and use the context switching method. But, I am unable to know what to do when a thread finishes its execution before the allotted time slot. The program is getting terminated. I actually want to reschedule all the threads, by calling the schedule function when the current thread gets terminated.
I found two ways to overcome this problem.
By calling explicitly thread_exit function at the end of the function that is being executed by the current thread.
By changing the stack contents such that the thread_exit function gets executed after the current function gets terminated.
But I am unable to find how to apply these solutions....
Anybody out there... plz help me...
It sounds like you have a bit of a design flaw. If I'm understanding you correctly, you're trying to implement a solution where you have threads that can be allocated to perform some task and after the task is complete, the thread goes idle waiting for the next task.
If that's true, I think I would design something like a daemon process or service that manages a queue for tasks coming in, a pool of threads responsible for executing the tasks with a controller that listens for new tasks.
I have a particularly long running method that I need to execute from my controller. The Method is in it's own Model. I am using an async controller, and I have the method setup using asyncFunc library to make it asynchronous. I have also tried invoking it on it's own process. The problem is I want to controller to go ahead and return a view so the user can continue doing other things as the method will notify the user it is completed or has any errors via e-mail.
The problem is even thogh it is an asynchronous method the controller will not move forward to return the view until the process is done. 15+ mins. and if you navigate to a different page the method stops trying to execute.
so how can I get the method to execute as a worker and free up the controller?
Any Help would be greatly appreciated.
all the best,
Chase Q, Aucoin
Use ThreadPool.QueueUserWorkItem() as a fire-and-forget approach in the ASPX page.
Do the long-running work in the WaitCallback you pass to QUWI.
when the work is complete, that WaitCallback can send an email, or whatever it wants.
You need to take care to handle the case that the w3wp.exe is stopped during the 15 minute run. What will you do if the work is 2/3 complete? Some options are, making the work restartable, or just allowing the interrupted work to be forgotten.
Making it restartable might mean, when w3wp.exe restarts, your ASP.NET logic makes sure to begin again, any work that was interrupted. It might mean that your ASP.NET logic sets "syncpoints" so that it knows where to restart.
If you want the restartable option, you might think about Workflow, which is specifically designed for this purpose - maintaining state of long-running workflows, restarting automatically, and so on. If you use Workflow, you can set it to run asynchronously, and you may decide you do not need QueueUserWorkItem.
see also:
Moving a time taking process away from my asp.net application
the Workflow Foundation tag
This will help > http://msdn.microsoft.com/en-us/library/ms227433.aspx
It is the standard way of running a background process on the server in the .NET stack.
I don't know why, but I still live in conviction that this should not be done. Executing background threads in ASP.NET smells. You will also steal threads from ASP.NET thread pool which is controlled by IIS. It can decide that something is wrong with your worker process and restart it any time just to keep memory consumption, processing time consumption or thread consumption low. If you need background logic create custom NT service and call the process on that service either via old .NET remoting or WCF.
Btw. approach I described is used frequently in commercial applications and those which doesn't use it often self-host the whole web server.