Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task Handling on Application Shutdown

I have a .Net (v4.0) Windows Service Application that spins of a tpl task at the beginning that performs certain, long running activities and basically stays alive for the application's life time and as such is created with the TaskCreationOptions.LongRunning parameter value.

Whenever the service is stopped and the .OnStop() method is called, I .Cancel() the CancellationToken(Source) I handed over to the worker task when I created it and I want it's .OnlyOnCanceled(...) continuation task to run.

The thing is, the service/process shuts down without that continuation task to run through "entirely" - sometimes it quits rather quickly, sometimes it runs through completely, sometimes it doesn't.

This does make sense to me as that particular task is probably sitting on another thread than the main one and thereby has no way of "stalling"/blocking that main one to end.

As I do not have a SynchronizationContext in that windows service application I can't tell that continuation task to run there/on the main thread so I was wondering: how would I do that?

And more precisely, what's the best practice to handle an application shutdown with running tpl tasks?

like image 404
Jörg Battermann Avatar asked Aug 25 '12 08:08

Jörg Battermann


2 Answers

You'll have to wait for your task to complete in the OnStop method (or OnPause and OnShutdown).

You have about 20 seconds to do whatever you need in OnStop. If you don't think your thread will complete in 20 seconds, you should call RequestAdditionalTime. As soon as you return from OnStop your service process can be terminated.

Using ContinueWith will asynchronously invoke the delegate passed to it, regardless of whether you pass ExecuteSynchronously or use a SynchronizationContext. As soon as the ContinueWith executes, assuming that's the last line of OnStop, OnStop return and returns control to the SCN (well, ServiceBase, but it sets your service's state to STOPPED and returns control to the SCM to presumably terminate your process.

ExecuteSynchronously means that the continuation runs synchronously with regard to the task it's continuing from. i.e. run on the same thread as the task (if possible). The task is likely not running on the thread that is calling ContinueWith (otherwise it couldn't call ContinueWith) so ExecuteSynchronusly doesn't mean synchronously with regard to the call to ContinueWith.

You need to do something like:

RequestAdditionalTime(TimeSpan.FromSeconds(30).Milliseconds);
cancellationToken.Cancel();
task.Wait();

in OnStop, the Wait means you won't exit from OnStop until your task completes (or it takes longer than 30 seconds and your process gets terminated)

like image 98
Peter Ritchie Avatar answered Oct 20 '22 20:10

Peter Ritchie


This happens so because the continuation task also runs asynchronously. In order for it to block you need to specify task continuation option:

...
t.ContinueWith(ct => {...}, TaskContinuationOptions.ExecuteSynchronously);
like image 45
oleksii Avatar answered Oct 20 '22 19:10

oleksii