Reputation: 43
I have a timer using which i am calling a method - {OnElapsedTime} And this should responsible for database access and updation for every interval of time.
protected override void OnStart(string[] args)
{
try
{
ServiceLogFile("Service is started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = Int32.Parse(ConfigurationManager.AppSettings["tracktime"]); //number in miliseconds
timer.Enabled = true;
}
catch(Exception ex)
{
ServiceLogFile("Error in {OnStart} :" + ex.ToString());
}
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
try
{
ServiceLogFile("Check for Database values - " + DateTime.Now);
th = new Thread(new ThreadStart(Autocancellation));
int ThreadID = Thread.CurrentThread.ManagedThreadId;
ServiceLogFile("Thread ID = " + ThreadID);
th.Start();
}
catch (Exception ex)
{
ServiceLogFile("Error in {OnElapsedTime} :" + ex.ToString());
}
}
public void Autocancellation()
{
try
{
lock (this)
{
//connection to database
//select Query and update
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message());
}
}
If we can see the above code - I am creating a new thread for every OnElapsedTime call.
Please help me with creating a single thread outside of this method or anywhere and using the same instance inside {OnElapsedTime} whenever this method is being called (In my case - 5 seconds)
Upvotes: 0
Views: 105
Reputation: 10401
Assuming
the simplest (or rather the simplest without any additional libraries) way would be to use Task, TaskCancellationSource and a timer with AutoReset = false
public class Service
{
private Task _job;
private CancellationTokenSource _cancellationTokenSource;
private readonly System.Timers.Timer _timer;
public Service()
{
_timer = new System.Timers.Timer();
{
_timer.AutoReset = false;
_timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
_timer.Elapsed += OnElapsedTime;
}
}
public void Start()
{
Console.WriteLine("Starting service");
_timer.Start();
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
Console.WriteLine("OnElapsedTime");
if (_job != null)
{
CancelAndWaitForPreviousJob();
}
Console.WriteLine("Starting new job");
_cancellationTokenSource = new CancellationTokenSource();
_job = Task.Run(
() => ExecuteJob(_cancellationTokenSource.Token),
_cancellationTokenSource.Token);
_timer.Start();
}
private void CancelAndWaitForPreviousJob()
{
_cancellationTokenSource.Cancel();
try
{
Console.WriteLine("Waiting for job to complete");
_job.Wait(
millisecondsTimeout: 5000); // Add additional timeout handling?
}
catch (OperationCanceledException canceledExc)
{
Console.WriteLine($"Cancelled the execution: {canceledExc}");
}
catch (Exception exc)
{
Console.WriteLine($"Some unexpected exception occurred - ignoring: {exc}");
}
}
private void ExecuteJob(CancellationToken cancellationToken)
{
Console.WriteLine("ExecuteJob start");
try
{
for (var i = 0; i < 10; i++)
{
Console.WriteLine($"Job loop Iteration {i}");
if (cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Cancellation requested - ending ExecuteJob");
return;
}
Thread.Sleep(1000);
}
}
finally
{
Console.WriteLine("ExecuteJob end");
}
}
}
While it is a working solution you may be interested in Quartz.net - it has only a moderate learning curve and it is designed exactly for such scenarios.
P.S.: Also it seems that your application is a service based on https://learn.microsoft.com/en-Us/dotnet/api/system.serviceprocess.servicebase?view=netframework-4.8. In such a case you may be interested in topshelf - it greatly simplifies a lot of things related to services.
Upvotes: 1