Saturday, June 29, 2019

Long-Running Process On A Timer

I wrote a blog post a few years ago called Fire and Forget (https://geek-goddess-bonnie.blogspot.com/2017/03/fire-and-forget.html). It was about using Task.Run() to initiate a long-running process that doesn't need to be monitored by the user (like maybe running SQL scripts or Stored Procedures). The gist of that post was that using a Task.Run() runs the process in a separate thread (so it won't block the UI, if you're running from a UI) and it just does its thing without interrupting the rest of your program.

The post I'm writing now is slightly different, in that we want to run long-running processes, but we want to run them at short intervals. For example, to run a SQL Stored Procedure every second that will clean up old data in your database. Say that the Stored Proc *sometimes* finishes in that one second interval, but sometimes it takes more than a second. If this is the case, you don't want it to start the next iteration every second ... you'd want it to start the when the previous one finishes ... even if that previous one is taking 10 seconds.

An easy way to accomplish this is to use the System.Threading.Timer. Everything that runs in the Timer's Callback is run in a separate thread:

private long TIME_INTERVAL_IN_MILLISECONDS = 1000; // 1 second
private System.Threading.Timer timerRunLongProcess;
private void BtnStart_Click(object sender, EventArgs e)
{
this.timerRunLongProcess = new System.Threading.Timer(RunLongProcess, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}
private void RunLongProcess(object state)
{
// Here you would put the code that runs a long process, maybe a call to a SQL Stored Proc or whatever it may be
// This will actually run on a separate thread and won't interfere with the UI thread or the rest of your application
// ...
// You can simulate a long-running process like this:
Console.WriteLine("It's time! Time is " + DateTime.Now.ToLongTimeString());
Thread.Sleep(5000); // 5 seconds
Console.WriteLine("Done! Time is " + DateTime.Now.ToLongTimeString());

// This will get the timer going again for the next 1 second
this.timerRunLongProcess.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}


Happy coding!  =0)