4
\$\begingroup\$

I'd like your opinion on something. I have the following class:

public class ApplicationClock
{
    void tick(object _)
    {
        lock (tickLock)
        {
            try
            {
                MessageBroker.Publisher.Publish(new Tick());
            }
            catch (Exception e)
            {
                this.Logger().Error("Application clock tick error", e);
                //who knows why this happened, let's try and restart
                if (ticker != null) ticker.Dispose();
                Start();
            }
        }
    }
    readonly Object tickLock = new Object();
    Timer ticker = null;
    public ApplicationClock Start()
    {
        ticker = new Timer(tick, null, 0, 60*1000);
        return this;
    }
}

launched from the MvcApplication bootstrapper

...
ApplicationClock clock;
protected void Application_Start() 
{
   //...
   clock = new ApplicationClock().Start();
}

I realize that a service and some sort of inter-process communication (whether windows inter-process communication, HTTP, or something else) is more standard and reliable but I have a frequently changing team and don't want to add another step that is necessary to run the app.

This seems to work but I've only launched it in a dev scenario. Am I missing anything that would cause problems in production?

That's a System.Threading.Timer by the way.

\$\endgroup\$
4
  • \$\begingroup\$ If it's launched from the bootstrapper and there is only ever one instance launched at app start is there any need to provide locking? \$\endgroup\$
    – dreza
    Sep 7, 2012 at 19:27
  • \$\begingroup\$ @dreza - just a precaution if it is in the process of crashing and restarts, or if a tick takes longer than a minute for some reason. \$\endgroup\$ Sep 7, 2012 at 19:58
  • 1
    \$\begingroup\$ Why exactly are you even trying to do this? Also... The System.Diagnostics.Stopwatch class is great for measuring time taken. \$\endgroup\$ Sep 8, 2012 at 0:06
  • \$\begingroup\$ I am doing a similar project and used the Stopwatch. codereview.stackexchange.com/questions/55059/… \$\endgroup\$
    – ADH
    Jun 24, 2014 at 16:43

2 Answers 2

5
\$\begingroup\$

Looks mostly ok, just some issues around coupling:

Consider one of the following

  1. Pass MessageBroker.Publisher via the ApplicationClock constructor as an external dependency (preferably an interface). This will make the current implicit dependency explicit and visible which should yield in better maintenance in the future and easier unit testing.
  2. Pass the tick handler in as an Action parameter - no dependency on a specific object at all.
  3. Expose a ClockTick event and raise the event handler on tick. This way anyone interested in the clock can subscribe and the clock doesn't need to know about them at all.

Also your tick interval is hard coded, it should be passed in as parameter.

\$\endgroup\$
1
\$\begingroup\$

A few limitations that I've discovered since then.

This will work. However, it is subject to all the Asp.Net (currently 4.5) limitations.

  • You have no control over when IIS might decide to kill your process. Do not run anything in this manner that has to run to completion
  • You have no control over whether your App Pool is running at any given time. If your application has not received any requests in a while, IIS might shut it down. When it is started by IIS at the next request the Tick timer will start again, but it might have been hours or even days since it ran last.

In other words, this methodology is good for idempotent, non-mandatory tasks such as "clean up the temp directory" or "remove any unused profile images from the file system"

\$\endgroup\$
4
  • 1
    \$\begingroup\$ when setting IIS startMode to alwaysRunning it seem the problem is resolved \$\endgroup\$
    – Sherlock
    Aug 13, 2014 at 22:47
  • \$\begingroup\$ @Sherlock I don't see how that is possible. Something can still throw an exception that would crash the process. Can you explain a bit about how it would work? \$\endgroup\$ Aug 14, 2014 at 2:38
  • \$\begingroup\$ the exception can happen any ways try to catch it and handle that, putting the app pool to alwaysrunning, will make sure the tick will still run even if there are no requests \$\endgroup\$
    – Sherlock
    Aug 14, 2014 at 4:06
  • \$\begingroup\$ Ah I see. I would probably not depend on that but that does sound handy. Eg. I probably wouldn't depend on that to send weekly invoices but it sounds good for cleanup and non-critical sync-ing processes. \$\endgroup\$ Aug 14, 2014 at 4:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.