0

I have a Windows service, developed in C#, which does some calculation on data at equal intervals of time say 30 mins. It fetches the data from database and calls a method CalcData() which does some business logic calculations.

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                AutoCalExecution ae = new AutoCalExecution();
                ae.FetchData();
                ae.CalData();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);                
            }
            Console.ReadLine();
        }
 }

 class AutoCalExecution
{
    public void FetchData()
    {
        // fetch data from db
    }

    public void CalData()
    {
        line1;
        line2;
        line3;
        line4; // this line has som expression which actually does the calculation. 
        line5;
    }  
}

I have given the template of the code which I'm using. In CalData(), line4 is where the calculation is happening. The calculation typically takes 10 mins to be done. So line4 is executed for 10mins.

There are some scenarios where the calculation might take more than 10 mins. In that case I want to cancel the execution and go to line5 after certain amount of time, say 15 mins.

To summarize I want to set a timeout time for line4 for 15 mins(which can be configured based in requirement), If it doesn't finish with in 15 mins, it has to stop and come to line5.

 public void CalData()
    {
        line1;
        line2;
        line3;
        if ( set time to 15 mins exceeds){
            line4; // this line has some expression which actually does the calculation.    
        }
        else 
        {
            Log (Line4 execution did not complete in stipulated time);
        }
        line5;
    }

How do I set that condition in C#?

Update

This is something I tried:

var task = Task.Run(() => CalData());
                        if (task.Wait(TimeSpan.FromMinutes(Convert.ToDouble(timeout))))
                        {
                            if (task.Result)
                            {
                                log.Info("Completed");
                            }
                            else
                            {
                                log.Error("Not successful");                                
                            }
                        }

But the problem here is I want line5 to get executed in this method if line 4 doesn't finish. Is there a way I can write this similar code for a piece of code/snippet, instead of whole method?

halfer
  • 19,824
  • 17
  • 99
  • 186
CrazyCoder
  • 2,194
  • 10
  • 44
  • 91
  • Does this answer your question? [Set timeout to an operation](https://stackoverflow.com/questions/2265412/set-timeout-to-an-operation) – Lucifer Mar 16 '20 at 10:36
  • You can use `Task` and set the `Timeout`. This might help https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout – BytesOfMetal Mar 16 '20 at 10:36
  • 3
    There is no built in method of killing of a statement if it takes too long. The framework level ways of killing such operations are not advisable. The best answer is "don't *kill* the operation, but *cooperate* with it". Write the code so that it can be aborted after a time, and the typical way of doing it these days is through using a TaskCancellationToken. – Lasse V. Karlsen Mar 16 '20 at 10:38
  • I have updated the answer to what I have done. – CrazyCoder Mar 16 '20 at 10:42

2 Answers2

0

I think you want something like this:

var work = Task.Run(() => line4);
if (work.Wait(TimeSpan.FromMinutes(10)))
{
      // Work completed within the timeout
}
else
{
     // Work did not complete within the timeout
}

Note that this will not actually stop the 'DoWork' code from running, it will continue on a worker thread until it is done. Also note that using 'Wait' risks deadlocks if used improperly, see Don't Block on Async Code.

If you actually want to cancel the processing you should give DoWork a cancellationToken and make the processing abort when the token is cancelled. There are also solutions to abort a running thread, but this is not recommended.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • This is what I'm currently doing. I do not want to entire method to run as a task. I want only one line of the method to run as a task. – CrazyCoder Mar 16 '20 at 11:55
  • Then run the whole block in place of 'line4', and replace 'DoWork' with the code for 'line4'. – JonasH Mar 16 '20 at 13:25
0

Make line4 into a task.

Make the task cancellable by a cancellation token.

Use a cancellation token which cancels itself after 10mins (configured time).

https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource.cancelafter?view=netframework-4.8

https://binary-studio.com/2015/10/23/task-cancellation-in-c-and-things-you-should-know-about-it/

weichch
  • 9,306
  • 1
  • 13
  • 25