0

I am having an issue with the a Service I used to perform automated tasks. The service uses a Timer and executes after 20 seconds.

The function that is executed opens the database, reads from it, sends the values through the network, receives a response and updates the database with that response.

Its been working well until I wanted to carry out the automated tasks for about 1000 rows in the database and the system 'failed'. After checking my logs, I found out that the function executes after the interval even while a previous instance is still executing. The function is supposed to send a message and some clients complained of not getting a message while others got as much as six time.

Is there any simple and efficient way to make sure the function will not run if a previous instance is still running.

If I start and stop the time in the function, it will only add the "passed" time to the interval

Here is the code

public partial class Service1 : ServiceBase
{
    private Timer timer1 = null;

    public Service1()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        timer1 = new Timer();
        this.timer1.Interval = 20000;
        this.timer1.Elapsed += new  System.Timers.ElapsedEventHandler(this.timer1_Tick);
        timer1.Enabled = true;
        Library.WriteErrorLog("service has started");
    }

    private void timer1_Tick(object sender, ElapsedEventArgs e)
    {
        try
        {
        //retrieve data from database
        //read rows

        //Loop through rows
        //send values through network
        //receive response and update db
        }
        catch (Exception ex)
        {
            Library.WriteErrorLog(ex);
        }
    }
}

    protected override void OnStop()
    {
        timer1.Enabled = false;
        Library.WriteErrorLog("service has stopped");
    }
}
Arno
  • 4,994
  • 3
  • 39
  • 63
elfico
  • 450
  • 1
  • 6
  • 13
  • Would stopping the timer in your tick before doing other things and then starting it again in a ```finally``` suffice? Or do you want to keep the timer running no matter what? This would ensure that only one timer will ever be running at any given time. – Kevin Lee Jul 29 '16 at 10:37
  • Thanks for the response @Kevin Lee. – elfico Aug 08 '16 at 15:33

2 Answers2

2
private void timer1_Tick(object sender, ElapsedEventArgs e)
{
    Timer timer = sender as Timer;
    timer.Enabled = false;  // stop timer
    try
    {
         //retrieve data from database
         //read rows

         //Loop through rows
         //send values through network
         //receive response and update db
     }
     catch (Exception ex)
     {
         Library.WriteErrorLog(ex);
     }
     finally
     {
         timer.Enabled = true;   // start timer again, no overlapping
     }
 }
1

You are using the multi-threaded System.Timers.Timer which calls the timer1_Tick callback on a new thread from the ThreadPool on each Elapsed event. Use a variable to synchronize the execution.

   public partial class Service1 : ServiceBase
    {

        private Timer timer1 = null;
        private long isTaskRunning = 0;

        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            timer1 = new Timer();
            this.timer1.Interval = 20000;
            this.timer1.Elapsed += new  System.Timers.ElapsedEventHandler(this.timer1_Tick);
            timer1.Enabled = true;
            Library.WriteErrorLog("service has started");
        }

        private void timer1_Tick(object sender, ElapsedEventArgs e)
        {
            try
            {

            if (Interlocked.CompareExchange(ref isTaskRunning, 1, 0)==1)
            {
             return;
            }

            //retrieve data from database
            //read rows

            //Loop through rows
            //send values through network
            //receive response and update db
            }
            catch (Exception ex)
            {
                Library.WriteErrorLog(ex);
            }
            finally
            {
             Interlocked.Exchange(ref isTaskRunning, 0);
            }
        }
    }

        protected override void OnStop()
        {
            timer1.Enabled = false;
            Library.WriteErrorLog("service has stopped");
        }
    }
radianz
  • 71
  • 5
  • I used `System.Timers` for the code but `InterLock` is method in `System.Threading.Timer`. Will this not cause a conflict? Sorry for my many questions, I am bit new to Threading. Thanks – elfico Aug 05 '16 at 10:33
  • There won't be any conflict. The callback will not be executed by multiple threads in the same time. That is prevented by the Interlocked methods – radianz Aug 05 '16 at 18:11
  • Thanks for the response. – elfico Aug 08 '16 at 15:33