Windows Service that runs Periodically

…衆ロ難τιáo~ 提交于 2019-11-27 10:22:08

问题


I'm writing a windows service that once started will run every X hours. The process it completes is fairly intensive, so I want to use a background worker. I'm using a Settings file to store both the hours between runs and the last time the service ran.

I'm not exactly sure the best way to do this - that is, I want the service to idle using as few resources as possible, and when it runs, it needs to run in the background worker, report what it did, and then go back into idle mode.

I've thought about using 2 background workers. The first worker would be a private local variable for the service that runs something like this:

while (true)
{
      //create new background worker and run

      Thread.Sleep(Settings.Default.SleepTimeHours * 3600000);
}

with a sub worker that is created each iteration of the loop, and destroyed when completed. To support cancellation, I think I would have to have a local instance of the second worker available in the service, but it will be null if the process currently is not running. When the secondary worker completes, it would send out my reporting, set the last run time in the settings file, and then dispose of the worker and set the reference to null.

I'm wondering if there is a better way to do this or a best practice.

Thanks


回答1:


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

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




回答2:


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




回答3:


Consider a job scheduler like Quartz.Net.

http://quartznet.sourceforge.net/




回答4:


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.
        }
    }
}



回答5:


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();
}



回答6:


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.




回答7:


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/




回答8:


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.




回答9:


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.




回答10:


Use a timer to do this.




回答11:


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.




回答12:


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);                
}    



回答13:


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;

    }

}



来源:https://stackoverflow.com/questions/1498498/windows-service-that-runs-periodically

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