0

I have a windows service that should poll a database for every 5 seconds for the new entries and update the log file.

I am using System.Timers.Timer class to call my Database method and calling Autocancellation for every 5 seconds.

 protected override void OnStart(string[] args)
 {
     try
     {
            ServiceLogFile("Service is started at " + DateTime.Now);
            timer.Elapsed += new ElapsedEventHandler(Autocancellation);
            timer.Interval = Int32.Parse(ConfigurationManager.AppSettings["tracktime"]); //number in miliseconds 
            timer.Enabled = true;
      }
      catch(Exception ex)
      {
           ServiceLogFile("Error in {OnStart} :" + ex.ToString());
      }
  }

  public void Autocancellation(object source, ElapsedEventArgs e)
  {
        try
        {
            lock (this)
            {

                //Database accesss
                //select statement 

                //Adding to Data table 
                if(dt.Rows.Count>0)
                {
                    //Update Statements 
                }
                else
                {
                     ServiceLogFile("There is no orders in the table Thread id :" +Thread.CurrentThread.ManagedThreadId);
                 }
              }
       }
   }

Autocancellation method will be having database access and update statements.

Expected Workflow -

It should update all the entries in the database and return back to the onStart method and poll for every 5 seconds.

Issue -

Whenever it completes updating the rows and if it has time (like if it finishes the updation statement in 2 mins at the last Iteration) and remaining 3 mins it will print "There is no orders in the table". I am not able to stop printing this until it finishes whole its timer.

I tried stopping the timer - But this leads to it will never poll the database again from onStart method.

Here is the sample of logs

When updation starts -

Service is stopped at 8/4/2019 1:34:15 PM
Service is started at 8/4/2019 1:34:28 PM
Database check :8/4/2019 1:34:33 PM
{INFO} Cancelled Order {AccessionID} : A1
{INFO} Cancelled Order {AccessionID} : A2
{INFO} Cancelled Order {AccessionID} : A3

End of Iteration -

{INFO} Cancelled Order {AccessionID} : A49997
{INFO} Cancelled Order {AccessionID} : A49998
{INFO} Cancelled Order {AccessionID} : A49999
{INFO} Cancelled Order {AccessionID} : A50000
Database check :8/4/2019 1:51:53 PM
There is no orders in the table Thread id :4
Database check :8/4/2019 1:51:53 PM
There is no orders in the table Thread id :3
Database check :8/4/2019 1:51:53 PM
There is no orders in the table Thread id :7

If we can see the above logs its looping in the same method to print no records. I tried with killing thread and return statements. Nothing worked.

After this Iteration time (5 seconds) This will be returned to the onStart and polls for 5 seconds correctly and logs are perfect -

Database check :8/4/2019 1:52:04 PM
There is no orders in the table Thread id :96
Database check :8/4/2019 1:52:09 PM
There is no orders in the table Thread id :97
Database check :8/4/2019 1:52:14 PM

Help in stopping the timer for the running instance and it should poll back as expected.

Nagendra Bhat
  • 43
  • 1
  • 9

1 Answers1

2

I would set the AutoReset property to False and re-start the timer after there are no more records. The reason for this is your Autocancellation might be called multiple times from different threads while you are busy processing the records.

From MSDN:

Gets or sets a Boolean indicating whether the Timer should raise the Elapsed event only once (false) or repeatedly (true).

protected override void OnStart(string[] args)
 {
     try
     {
            ServiceLogFile("Service is started at " + DateTime.Now);
            timer.AutoReset = false;
            timer.Elapsed += new ElapsedEventHandler(Autocancellation);
            timer.Interval = Int32.Parse(ConfigurationManager.AppSettings["tracktime"]); //number in miliseconds 
            timer.Enabled = true;
            timer.Start();
      }
      catch(Exception ex)
      {
           ServiceLogFile("Error in {OnStart} :" + ex.ToString());
      }
  }

public void Autocancellation(object source, ElapsedEventArgs e)
{

    try
    {
        lock (this)
        {

            //Database accesss
            //select statement 

            //Adding to Data table 
            if(dt.Rows.Count>0)
            {
                //Update Statements 
            }
            else
            {

                 ServiceLogFile("There is no orders in the table Thread id :" +Thread.CurrentThread.ManagedThreadId);
             }
          }
   }
   finally
   {
// in anycase, start the timer again. In this pattern, you will not get
// any calls until the processing is finished.    
            timer.Start();
       }
    }
EylM
  • 5,967
  • 2
  • 16
  • 28
  • So you need the execution of the timer all the time on order to check for the new data. So, in this case -> remove the log file. I think what was happening to you in the first example is that your timer delegate was called multiple times from different threads. – EylM Aug 04 '19 at 17:14
  • Thanks for the response. I could start my thread initially, however, After completing updating my records - it stopped the timer. And i have added some more records to check whether my method gets up to update it. But, Couldn't succeed with updating rows. – Nagendra Bhat Aug 04 '19 at 17:14
  • Okay.. I think i need the log file there to print "No records" Because - Lets assume we have some data in the database to update and it did its job for this time. And later (after 5 or 10 seconds) it has to check whether the data is present if so it has to update or log - there is no data at this moment.. – Nagendra Bhat Aug 04 '19 at 17:17
  • In addition to your answer - Can you please explain me, is it possible to create a single thread for the method that would be called for every interval of a timer? – Nagendra Bhat Aug 04 '19 at 17:20
  • Check the updated answer. It will prevent multiple calls to the delegate. – EylM Aug 04 '19 at 17:21
  • Sure. Changed my code and kept it for running. I will get back to you in 5 mins. Thanks a lot for mentoring me for this issue. – Nagendra Bhat Aug 04 '19 at 17:24
  • It did work. Thank you so much for the code. I have one last concern - Can you please answer it? Can you please explain me, is it possible to create a single thread for the method that would be called for every interval of a timer? – Nagendra Bhat Aug 04 '19 at 17:48
  • 1
    Try this: https://stackoverflow.com/questions/5497466/c-sharp-single-threaded-timer – EylM Aug 04 '19 at 17:50