Windows Service that runs Periodically

橙三吉。 提交于 2019-11-28 17:04:47
CitizenBane

I typically use a Timer, then stop it when the process starts to run.

Here's an article that explains how to do it.

This is not a very good idea, since you lock your thread for the full period of "SleepTimeHours" and you won't be able to even stop the service in the meantime.

You could either make this service so that it would sleep for e.g. 5 seconds and then check whether it's time to get back to work, and if not, sleep another 5 seconds (that would give you the necessary responsiveness, if you need to stop the service).

OR: you might be better off just writing a console app that can be scheduled using the Windows "scheduled tasks" feature in order to be run every x hours. That way, you won't be blocking or using any system resource if your app isn't doing anything......

Marc

Consider a job scheduler like Quartz.Net.

http://quartznet.sourceforge.net/

How about something more like this:

    public class LongRunningService : ServiceBase
{
    System.Threading.Thread processThread;
    System.Timers.Timer timer;
    private Boolean Cancel;

    protected override void OnStart(string[] args)
    {
        timer = new Timer(Settings.Default.SleepTimeHours * 3600000);
        timer.Elapsed += new ElapsedEventHandler(timer_Tick);
        timer.Start();

        Cancel = false;
    }

    protected override void OnContinue()
    {
        timer.Start();
    }

    protected override void OnPause()
    {
        timer.Stop();
    }

    protected override void OnStop()
    {
        if (processThread.ThreadState == System.Threading.ThreadState.Running)
        {
            Cancel = true;
            // Give thread a chance to stop
            processThread.Join(500);
            processThread.Abort();
        }
    }

    void timer_Tick(object sender, EventArgs e)
    {
        processThread = new System.Threading.Thread(new ThreadStart(DoWork));
        processThread.Start();
    }

    private void DoWork()
    {
        try
        {
            while (!Cancel)
            {

            if (Cancel) { return; }
            // Do General Work

            System.Threading.Thread.BeginCriticalRegion();
            {
                // Do work that should not be aborted in here.
            }
            System.Threading.Thread.EndCriticalRegion();
            }

        }
        catch (System.Threading.ThreadAbortException tae)
        {
            // Clean up correctly to leave program in stable state.
        }
    }
}

Use an approach based on the System.Threading.WaitHandle approach.

using System.Threading;
private Thread _thread;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private ManualResetEvent _scheduleEvent = new ManualResetEvent(false);
private System.Timers.Timer _scheduleTimer = new System.Timers.Timer();
protected override void OnStart(string[] args)
{
    // Configure the timer.
    _scheduleTimer.AutoReset = false;
    _scheduleTimer.Interval = 120000; // 2 minutes in milliseconds
    _scheduleTimer.Elapsed += delegate { _scheduleEvent.Set(); }

    // Create the thread using anonymous method.
    _thread = new Thread( delegate() {
        // Create the WaitHandle array.
        WaitHandler[] handles = new WaitHandle[] {
            _shutdownEvent,
            _scheduleEvent
        };
        // Start the timer.
        _scheduleTimer.Start();
        // Wait for one of the events to occur.
        while (!_shutdownEvent.WaitOne(0)) {
            switch (WaitHandle.WaitAny(handles)) { 
               case 0:  // Shutdown Event
                   break;
               case 1:  // Schedule Event
                   _scheduleTimer.Stop();
                   _scheduleEvent.Reset();
                   ThreadPool.QueueUserWorkItem(PerformScheduledWork, null);
                   break;
               default:
                   _shutdownEvent.Set(); // should never occur
            }
        }
    } );
    _thread.IsBackground = true;
    _thread.Start();
}
protected override void OnStop()
{
    // Signal the thread to shutdown.
    _shutdownEvent.Set();
    // Give the thread 3 seconds to terminate.
    if (!_thread.Join(3000)) {
        _thread.Abort(); // not perferred, but the service is closing anyway
    }
}
private void PerformScheduledWork(object state)
{
    // Perform your work here, but be mindful of the _shutdownEvent in case
    // the service is shutting down.
    //
    // Reschedule the work to be performed.
     _scheduleTimer.Start();
}

You don't really want to use background worker. Background workers are used when you have something going one at the foreground (such as UI) and you also want something else to be done on the background. In your case there's no foreground processing, all you have is a single job that you need to run every once in a while.

Also, don't bother with the sleeping business etc. Instead, use a scheduler framework, such as Quartz.NET to wake it up every once in a while. This way when your service starts it will initialize the scheduler and do absolutely nothing until scheduler wakes up. When scheduler wakes up it will call a method of an object that you tell it to call when you initialize it.

This way the service will barely consume any CPU when idle and work full steam when needed.

Blog.StackOverflow.com has an interesting article on using cache expiration to handle periodic tasks:

http://blog.stackoverflow.com/2008/07/easy-background-tasks-in-aspnet/

Someone had a similar question over on Super User. You could install a tool that monitors windows services. Something like Service Hawk would help you keep the services started, or allow you to schedule automatic restarts (possibly during the night) to keep the service running smoothly.

In my company, we rely on windows task scheduler to initiate the service, and then have the service shut itself down. This insures our service is always run at the right time and the scheduling system will allow reporting of success / failure etc.

Use a timer to do this.

I had the same discussion with colleagues around 1hour ago! I went with the while(_isPolling) option, because i needed the work to happen syncronously. I didnt want the same work being picked up by other thread (the Timer approach), and implementing extra locking for that seemed like a waste.

Tom

I applied a combination of the Timer and worker thread, and so far it works ok.

I set my timer to tick every minute, and, if the time matches the schedule time, I create my worker thread.

I used this technique in doing some housekeeping:

if (nowTimeVar.ToShortTimeString().CompareTo(houseKeep.ToShortTimeString()) == 0)
{
    myHouseKeeper = new clsHouseKeep(archiveFolder, lastday, myCounter, myLogger);                
}    

After Checking lot of tutorial i developed windows service which run periodically every 60 mins and it will start process in background and run Test.exe.

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


    public Scheduler()
    {
        InitializeComponent();
    }
    // Get the Exe path
    private string GetPath()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        return Path.Combine(Path.GetDirectoryName(assembly.Location), "Test.exe");

    }
    // you can right your own custom code
    // Above vista version the process works as Administrator- "runas" and in old OS it will Start process as per Administartor rights  
    public void startprocess()
    {
       // System.Diagnostics.Process.Start(GetPath());
        System.Diagnostics.Process process = null;
        System.Diagnostics.ProcessStartInfo processStartInfo;

        processStartInfo = new System.Diagnostics.ProcessStartInfo();

        processStartInfo.FileName = GetPath();

        if (System.Environment.OSVersion.Version.Major >= 6)  // Windows Vista or higher
        {
            processStartInfo.Verb = "runas";
        }
        else
        {
            // No need to prompt to run as admin
        }

        processStartInfo.Arguments = "";

        process = System.Diagnostics.Process.Start(processStartInfo);

    }
    // On start method will load when system Start 
    // timer1_tick Event will call every hour after once start the service automatically
    protected override void OnStart(string[] args)
    {
        //System.Diagnostics.Debugger.Launch();
        timer1 = new Timer();
        this.timer1.Interval = 3600000; //every 60 min
        this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Tick);
        timer1.Enabled = true;

    }

    // Timer1_tick will Start process every hour
    private void timer1_Tick(object sender, ElapsedEventArgs e)
    {
        //Write code here to do some job depends on your requirement
        startprocess();
    }
    // Method will stop the service
    // we have set the method stop service as false. so service will not stop and run every hour 
    protected override void OnStop()
    {
        timer1.Enabled = false;

    }

}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!