C# – Timer behavior when execution takes longer than span

cnettimerwindows-services

I'm writing windows service which will process "something" every couple minutes.

Here is some code:

public Service()
        {
            this.InitializeComponent();
            this.ServiceName = Name;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;

            this.eventLog.Source = Name;

            // initialize timer
            this.timer.Elapsed += this.TimerElapsed;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            if (this.processor.PrepareToRun())
            {
                this.processor.Run();
            }
        }

I wonder what will happen if this.processor.Run() will take long time and next TimerElapsed event will be raised? Will it skip? Will it wait and run ASAP after finished? Should I consider those scenarios and code for them?

I'm using System.Timers.Timer

EDIT:

private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            try
            {
                this.timer.Stop();
                if (this.processor.PrepareToRun())
                {
                    this.processor.Run();
                }
            }
            catch (Exception ex)
            {
                LoggingAndNotifications.LogAndNotify(ex);

            }
            finally
            {
                this.timer.Start();
            }
        }

EDIT 2

public Service()
        {
            this.InitializeComponent();
            this.ServiceName = Name;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;

            this.eventLog.Source = Name;

            // initialize timer
            this.timer.AutoReset = false;
            this.timer.Elapsed += this.TimerElapsed;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            try
            {
                if (this.processor.PrepareToRun())
                {
                    this.processor.Run();
                }
            }
            catch (Exception ex)
            {
                LoggingAndNotifications.LogAndNotify(ex);
                throw;
            }
            finally
            {
                this.timer.Start();
            }
        }

Best Answer

It'll call it again on another thread.

Depending on the nature of the operation you will want to either:

  1. Ignore this, if the code called is safe for multiple simultaneous calls then this may be fine. Of course, you have to know that it's fine.
  2. Lock on the timer-triggered operation. Be aware that you can end up with a queue of lots of pending operations, which is very bad.
  3. Lock on the timer-triggered operation, try to obtain the lock with a timeout of zero and if you fail then skip it - there's a thread still here from the last time.
  4. Have the timer as a one-off timer that you restart at the end of each call.
Related Topic