2014-05-21 8 views
3

저는 C#으로 작성한 Windows 서비스를 사용하고 있습니다. 그 뒤에는 FileSystemWatcher가 있습니다. FSW는 새 파일을 찾아 이에 따라 처리합니다. 서비스가 시작되면 기존 파일을 처리해야합니다. 콘솔 앱을 통해이 작업을 수행하면 모든 것이 예상대로 작동합니다.간단한 C# FileSystemWatcher Windows 서비스를 빠르게 시작하십시오.

그러나이 모든 것을 Windows 서비스에서 랩하려고 시도하면 내 첫 번째 문제는 Windows 서비스가 시작되지 않는다는 것입니다. 처음에는 많은 파일이 처리 되더라도 처리하는 데 너무 오래 걸렸기 때문에 시간이 초과되었습니다.

public WatcherService() 
{ 
    _log.Debug("WatcherService instantiated."); 
    _watcher = new FileSystemWatcher { Path = AppConfig.MonitorFolder, IncludeSubdirectories = true }; 

    // we want the watching to start BEFORE we process existing files 
    // because if we do it the other way, a file might get missed 
    _watcher.Created += File_OnChanged; 
} 

public void StartWatching() 
{ 
    _log.Debug("WatcherService started."); 
    // this kicks off the watching 
    _watcher.EnableRaisingEvents = true; 

    // process existing files 
    ProcessExistingFiles(AppConfig.MonitorFolder); 
} 

내 해결 방법은 FSW "보고"와 별도의 비동기 스레드에서 초기 파일의 처리와 같은 킥오프했다 : 여기

내 "보고"클래스에 대한 코드의 일부입니다 이 (내 Windows 서비스 코드) :

protected override void OnStart(string[] args) 
{ 
    _log.Debug("LoggingService starting."); 

    // kick off the watcher on another thread so that the OnStart() returns faster; 
    // otherwise it will hang if there are a lot of files that need to be processed immediately 
    Task.Factory.StartNew(() => _watcher.StartWatching()).ContinueWith(t => 
     { 
      if (t.Status == TaskStatus.Faulted) 
      { 
       _log.Error("Logging service failed to start.", t.Exception.InnerException ?? t.Exception); 
      } 
     }); 
} 

나는 Task.Factory.StartNew (에서 "StartWatching"방법)에 ONSTART()가 이해할 수 있도록, 타임 아웃 것을 포장하지 않은 경우. 하지만 이제는 StartWatching() 메서드가 호출되지 않습니다. 로그에 "LoggingService starting"이 표시되지만 "WatcherService started"는 표시되지 않습니다. (편집 : 참고로, Task.Run()도 시도했지만, 아무 소용이 없습니다.)

그게 뭐야? StartNew()가 수행하는 작업을 이해하지 못하거나 내가 성취하려는 작업을 수행하는 것이 더 좋습니다.

생각하십니까?

감사합니다.

+0

다른 조건문을 사용하고 출력 결과를 확인해보십시오 (아직 시도하지 않은 경우). –

답변

2

완전히 스레딩을 피할 수 있습니다. OnStart() 방법으로 기본 설정을 수행하면됩니다. 그 설정의 일부는 2 ~ 2 초 후에 꺼지는 타이머를 설정하는 것입니다.해당 타이머는 현재 스레드에서 실행될 수 있지만 서비스가 이 유휴이면 후에 발생합니다.

이렇게하면 문제가 해결되며 스레드로부터 안전한 코드를 작성하는 것이 더 쉽습니다.

+0

이것은 가장 쉬운 구현이었습니다. – ironfist

0

서비스는 가능한 한 빨리 OnStart에서 반환하도록 설계되어야합니다. 아마도 처음 30 초 이내에 내부에서는 초기화 작업 만 수행하면됩니다.

  1. 당신이 만약 (타이머 FileSystemWatching)를 장기 실행 작업에
    2. 시작 적어도 하나의 비동기 작업을 스레드를 생성
    1 :

    당신은 당신의 서비스를 시작하기위한 두 가지 방법을 사용할 수 있습니다 당신은 확실히 새 스레드 시작해야 장기 실행 작업이 : 귀하의 경우에는

    public void OnStart(string[] args) 
    { 
        var worker = new Thread(DoWork); 
        worker.Name = "MyWorker"; 
        worker.IsBackground = false; 
        worker.Start(); 
    } 
    
    void DoWork() 
    { 
        // long running task 
    } 
    
  2. 를, 당신의 장기 실행 작업은 파일 차에 대한보고 nges. 당신이 FileWatcher를 사용할 때, 당신은 ONSTART 방법 내부보고 파일을 시작하고 스레드 풀 사용하여 단기 실행 작업을 시작할 수 있습니다 : 나는 Task.Factory.StartNew 모르는

    protected override void OnStart(string[] args) 
    { 
        _log.Debug("LoggingService starting."); 
    
        _log.Debug("Initializing FileSystemWatcher ."); 
        _watcher = new FileSystemWatcher { Path = AppConfig.MonitorFolder, IncludeSubdirectories = true }; 
        _watcher.Created += File_OnChanged;  
        _watcher.EnableRaisingEvents = true; 
        _log.Debug("FileSystemWatcher has been started."); 
    
        ThreadPool.QueueUserWorkItem(ProcessExistingFiles, AppConfig.MonitorFolder); 
        _log.Debug("Processing of existing files has been queued."); 
    } 
    
    private void ProcessExistingFiles(object folderPathObj) 
    { 
        var folderPath = folderPathObj as string; 
        if (folderPath != null) 
        { 
        } 
    } 
    
+0

성능 관점에서 ThreadPool과 새로운 Thread를 만드는 것이 더 좋습니다. 일반적으로, 둘 사이의 차이점을 모른다면 (거의) 항상 ThreadPool을 사용하는 것이 좋습니다. 차이점에 관심이 있다면 여기에 StackOverflow에 대한 좋은 토론이 많이 있습니다. http://stackoverflow.com/questions/2049948/thread-pool-vs-thread-spawning – kape123

+0

@ kape123 어쨌든 스레드를 만들어야합니다. 또한 장기 실행 작업이므로 하나의 스레드 만 생성해야하므로 스레드 풀을 사용하는 대신 새 스레드를 만드는 것이 좋습니다 (http://stackoverflow.com/a/3344692/3523746) –

0

을 ...하지만 난이 다소 비슷한 서비스와 나는 ThreadPool을 이런 종류의 물건에 사용한다.

또한 StartWatching을 별도의 스레드에서 실행하는 것에 대해 알지 못합니다. ProcessExistingFiles를 별도의 스레드에 배치하는 방법에 대해 설명했습니다. 예 :

public WatcherService() 
{ 
    _log.Debug("WatcherService instantiated."); 
    _watcher = new FileSystemWatcher { Path = AppConfig.MonitorFolder, IncludeSubdirectories = true }; 

    // we want the watching to start BEFORE we process existing files 
    // because if we do it the other way, a file might get missed 
    _watcher.Created += File_OnChanged; 
} 

public void StartWatching() 
{ 
    _log.Debug("WatcherService started."); 
    // this kicks off the watching 
    _watcher.EnableRaisingEvents = true; 

    // process existing files 

    // keep in mind that method should be 
    // void ProcessExistingFiles(object param) 
    // in order to satisfy Waitcallback delegate 
    ThreadPool.QueueUserWorkItem(ProcessExistingFiles, AppConfig.MonitorFolder); 

    // since you are now starting async - be sure not to process files multiple times 
    // i.e. from File_OnChanged and ProcessExistingFiles 
}