tags:

views:

1583

answers:

7
+2  Q: 

Run once a day

Hi,

Is there any clever method out there to make my executeEveryDayMethod() execute once a day, without having to involve the Windows TaskScheduler?

Regards

/Anders

A: 

How about creating a thread that sleeps for an hour, and add one to a counter each time the thread wakes up. If counter Mod 24 = 0 then run the method, otherwise go back to sleep for an hour.

Mitch Wheat
That wont work correctly if the machine powers on/off during the course of the day.
Quibblesome
ah, but that wasn't part of the question!
Mitch Wheat
OK: Create a windows service (set to auto start on reboot), that sleeps for an hour. When it wakes up check the time elapsed since last method execution, if greater than or equal to 24 hours run the method and then sleep for an hour.
Mitch Wheat
@Quarrelsome: if the machine might be powered off, then the answer is "you can't ensure that the method is called once per day". Because the machine might be off all day ;-p
Steve Jessop
+1  A: 

If the time when it is run is not relevant and can be reset each time the program starts you can just set a timer, which is the easiest thing to do. If that's not acceptable it starts getting more complex, like the solution presented here and which still doesn't solve the persistence problem, you need to tackle that separately if you truly wish to do what Scheduled Tasks would. I'd really consider again if it's worth going through all the trouble to replicate a perfectly good existing functionality.

Here's a related question (Example taken from there).

using System;
using System.Timers;

public class Timer1
{
    private static Timer aTimer = new System.Timers.Timer(24*60*60*1000);

    public static void Main()
    {
        aTimer.Elapsed += new ElapsedEventHandler(ExecuteEveryDayMethod);
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program.");
        Console.ReadLine();
    }

    // Specify what you want to happen when the Elapsed event is 
    // raised.
    private static void ExecuteEveryDayMethod(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}
Vinko Vrsalovic
See comment @ZombieSheep
StingyJack
See first paragraph :-)
Vinko Vrsalovic
A: 

You could query time and run if your within some time frame, that way even if the machine goes off you'll call the method or use a timer like Vinko's suggestion.

But the better solution (akin to older CRON versions, so its a proven pattern) is to have some persistent data, with the cheapest solution I can think of right now being a blank file, check its last modified attribute, and if it hasn't been modified within the last 24 hours you touch it and run your method. This way you assure the method gets run first thing in the case the application is out for the weekend for example.

I've done this in C# before, but its was a year ago at another Job, so I don't have the code but it was about 20 lines (with comments and all) or so.

Robert Gould
+5  A: 

I achieved this by doing the following...

  1. Set up a timer that fires every 20 minutes (although the actual timing is up to you - I needed to run on several occasions throughout the day).
  2. on each Tick event, check the system time. Compare the time to the scheduled run time for your method.
  3. If the current time is less than the scheduled time, check a in some persistent storage to get the datetime value of the last time the method ran.
  4. If the method last ran more than 24 hours ago, run the method, and stash the datetime of this run back to your data store
  5. If the method last ran within the last 24 hours, ignore it.

HTH

*edit - code sample in C# :: Note : untested...

using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Timer t1 = new Timer();
            t1.Interval = (1000 * 60 * 20); // 20 minutes...
            t1.Elapsed += new ElapsedEventHandler(t1_Elapsed);
            t1.AutoReset = true;
            t1.Start();

            Console.ReadLine();
        }

        static void t1_Elapsed(object sender, ElapsedEventArgs e)
        {
            DateTime scheduledRun = DateTime.Today.AddHours(3);  // runs today at 3am.
            System.IO.FileInfo lastTime = new System.IO.FileInfo(@"C:\lastRunTime.txt");
            DateTime lastRan = lastTime.LastWriteTime;
            if (DateTime.Now > scheduledRun)
            {
                TimeSpan sinceLastRun = DateTime.Now - lastRan;
                if (sinceLastRun.Hours > 23)
                {
                    doStuff();
                    // Don't forget to update the file modification date here!!!
                }
            }
        }

        static void doStuff()
        {
            Console.WriteLine("Running the method!");
        }
    }
}
ZombieSheep
Clbluttic problem with Timer and elapsed... The check to see when it should first run has been excluded, or there is no invocation of the doStuff() method before the timer starts ticking. If you have a 24 hour wait, you will see the programs as 'dead' for a day.
StingyJack
Good point! As I said, it wasn't tested and I had completely forgotten to implement the 'first run' behaviour. My bad!
ZombieSheep
A: 

There may be problems if the computer reboots so you could run the application as a windows service.

HenryHey
+3  A: 

Take a look at quartz.net. It is a scheduling library for .net.

More specifically take a look here.

reshefm
"After more than two years of development, bug fixing and new features Quartz.NET has finally matured to version 1.0." I knew scheduling is a lot harder than it looks at first sight. Two years and for a clone!
Vinko Vrsalovic
Everyone forgot to mention that it is totally free with no GPL restrictions (Apache license :o)
wcm
A: 

Thanks all of you for taking the time to help me find a solution to my problem!

Anders R