2009-09-30 5 views
21

일단 시작된 Windows 서비스는 매 X 시간마다 실행됩니다. 완료 프로세스는 상당히 집중적이므로 백그라운드 작업자를 사용하고 싶습니다. 설정 파일을 사용하여 실행과 서비스가 실행 된 마지막 시간을 모두 저장합니다.주기적으로 실행되는 Windows 서비스

나는 이것을 할 수있는 최선의 방법이 확실하지 않다. 즉, 서비스가 가능한 한 적은 자원을 사용하여 유휴 상태로 있도록하고, 실행될 때 백그라운드 작업자로 실행해야한다. 그런 다음 유휴 모드로 돌아갑니다.

저는 2 명의 배경 작업자를 생각해 보았습니다. 루프의 각 반복을 생성, 완료되면 파괴 하위 작업자와

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

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

: 첫 번째 노동자는 전용 지역과 같이 뭔가를 실행하는 서비스에 대한 변수가 될 것입니다. 취소를 지원하려면 서비스에서 두 번째 작업자의 로컬 인스턴스를 사용할 수 있어야하지만 현재 프로세스가 실행되고 있지 않으면 null이됩니다. 보조 작업자가 완료되면 내보고를 보내고 설정 파일에서 마지막 실행 시간을 설정 한 다음 작업자를 처분하고 참조를 null로 설정합니다.

더 좋은 방법이나 최선의 방법이 있는지 궁금합니다.

덕분에 우리 회사에서

+0

- 내가 옵션으로, 그러나 건축가는 Windows 서비스가되고 싶어 것을 제안했다. – Josh

+2

@ Broken Bokken : 두 세계 모두의 베스트 : http://www.genericgeek.com/Enable-a-service-from-command-line;) – JustLoren

답변

33

일반적으로 타이머를 사용하고 프로세스가 시작될 때 타이머를 중지합니다.

여기에 how to do it을 설명하는 기사가 나와 있습니다.

+1

+1 : 좋은 자습서 링크 – Zenuka

+0

그 기사는 좋은 링크였습니다. 고맙습니다. – Josh

+0

그러나 나는 여전히 서비스가 Start(), Stop(), Reset() 등의 응답을 멈추게 할 수있는 타이머 이벤트 스레드를 잠글 것이라고 생각합니다. 서비스는 30 초 이내에 응답 할 수 있어야합니다. 스레드 비 블로킹 방식이 더 좋을 것입니다. – Ian

1

, 우리는 서비스를 시작하려면 Windows 작업 스케줄러에 의존하고 서비스 자체를 종료했다. 이것은 우리의 서비스가 항상 올바른 시간에 실행되도록 보장하며 스케줄링 시스템은 성공/실패 등을보고 할 수 있습니다.

+0

Quartz와 같이 멋지게 확장됩니다. –

+0

스케일 업을 의미합니다. 우리는 야간에 약 15 개의 서비스를 운영하고 주말에는 약 30 개의 서비스를 운영합니다. 얼마나 많은 서비스가 필요하다고 생각하십니까? lol – JustLoren

1

타이머를 사용하면됩니다.

13

"SleepTimeHours"의 전체 기간 동안 스레드를 잠그고 그 사이에 서비스를 중지 할 수 없기 때문에 이것은별로 좋은 생각이 아닙니다.

예를 들어이 서비스를 잠자기 상태로 만들 수 있습니다. 5 초 후에 다시 작동 할 시간인지 확인하십시오. 그렇지 않은 경우 5 초 동안 기다리십시오 (서비스를 중지해야하는 경우 필요한 응답 성이 제공됩니다).

또는 OR : x 시간마다 실행되도록 Windows "예약 된 작업"기능을 사용하여 예약 할 수있는 콘솔 앱을 작성하는 것이 좋습니다. 그런 식으로, 당신은

마크

+3

전체 X 시간을 자지 않는 것이 좋은 점. 고마워, 마크. – Josh

+1

while (true) 당신이 잠시 (_isPolling)를 추가하는 것보다는 서비스를 중지 할 때 멈추게 될 것이고 스레드가 결국 깨어날 때 끝날 것입니다 :) –

+0

서비스 대신 예약 된 작업 솔루션을 제안하려고했습니다 . – Philippe

10

는 Quartz.Net 같은 작업 스케줄러를 고려 ...... 차단 또는 앱이 아무것도하지 않는 경우 모든 시스템 자원을 사용하지 않습니다.

http://quartznet.sourceforge.net/

+0

저는 Timers로 작업하곤했지만 새 프로젝트에서는 Quartz.net을 사용하고 있습니다. 솔직히 cronTrigger를 사용하면 cron 문자열로 작업을 트리거 할 수 있습니다. 여기에 귀하의 제안에 감사드립니다! – Marc

2

당신은 정말 배경 노동자를 사용하지 않습니다. 배경 작업자는 UI와 같은 전경에서 뭔가 진행될 때 사용되며 백그라운드에서 다른 작업을 수행하기를 원할 때 사용됩니다. 귀하의 경우 전경 처리가 없으므로 한 번씩 실행해야하는 단일 작업 만 있으면됩니다.

또한 잠자기 등에 신경 쓰지 말고 Quartz.NET과 같은 스케줄러 프레임 워크를 사용하여 잠시 일어납니다. 이 방법은 서비스가 시작될 때 스케줄러를 초기화하고 스케줄러가 깨어날 때까지 아무 것도하지 않습니다. 스케줄러가 깨어 나면 초기화 할 때 호출하도록 지정한 객체의 메소드를 호출합니다.

이렇게하면 서비스가 유휴 상태 일 때 CPU를 거의 소비하지 않고 필요할 때만 작동합니다.

7

얼마나 더 이런 일에 대해 :

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

System.Windows.Forms.Timer 대신 System.Timers.Timer 클래스를 사용하는 것이 좋습니다. Forms.Timer는 System.Windows.Forms.dll을로드해야합니다.이 파일은 일반적으로 Windows 서비스에 필요한 것이 아닙니다. –

+0

사실 동의합니다. 예제를 업데이트했습니다. – Ian

+0

DoWork()의 ​​while (! Cancel) {}의 목적과 실행이 if (Cancel) {return;} 아래로 어떻게 이동합니까? 아마도 그 동안의 마지막 버팀대가 끝날 것입니다. – pug

1

했다 약 1 시간 전에 동료들과 함께! 나는 whileron (_isPolling) 옵션을 가지고 갔다. 왜냐하면 나는 syncronously 일어날 일이 필요했기 때문이다. 나는 다른 스레드 (Timer 접근법)에 의해 픽업 된 동일한 작업을 원했고 낭비처럼 보이는 추가 잠금을 구현하지 않았다.

4

System.Threading.WaitHandle 방식을 기반으로 한 접근 방식을 사용하십시오.

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

이것은 좋은 대답이며 IMHO는 선택한 대답보다 나은 해결책입니다. –

2

누군가가 수퍼 유저와 비슷한 질문을했습니다. Windows 서비스를 모니터하는 도구를 설치할 수 있습니다. Service Hawk과 같은 것이 서비스 시작을 유지하는 데 도움이되며, 서비스가 원활하게 실행될 수 있도록 자동 재시작 (야간에도 가능)을 예약 할 수 있습니다.

0

타이머와 작업자 스레드의 조합을 적용했으며 지금까지는 정상적으로 작동합니다.

매분마다 내 타이머를 설정하고, 시간이 일정 시간과 일치하면 작업자 스레드를 만듭니다. 내가 정기적으로 매 60 분을 실행하는 Windows 서비스를 개발

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

튜토리얼을 많이 확인 후 그리고 백그라운드에서 프로세스를 시작하고 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; 

    } 

}

관련 문제