0

I have a Windows service that just silently stops on its own. Here is the relevant code:

OnStart() method:

    protected override void OnStart(string[] args)
    {
        try
        {
            InitializeLogging();

            // we don't DO command line arguments
            if (args.Length > 0)
            {
                eventLog.WriteEntry("All command line arguments are ignored.  You must edit the app.config file manually to make changes to what watchers are run.");
                throw new ArgumentException("Command line arguments are ignored.");
            }

            ReadAppConfig();
            RecalculateStartTimes();
            InitializeWatchers();

        }
        catch (Exception e)
        {
            eventLog.WriteFormattedEntry("Error on Start: {0}", e.Message);
        }
        finally
        {
            eventLog.WriteEntry("Service start completed");
        }
    }

OnStop() method:

    protected override void OnStop()
    {
        eventLog.WriteEntry("Service stopped.");
    }

InitializeWatchers() method:

    private void InitializeWatchers()
    {
        try
        {

            var watchers = _watcherSection.Watchers.ToList<WatcherElement>();

            eventLog.WriteEntry(string.Format("Initializing {0} watchers.", watchers.Count()));

            var obsWatchers = watchers.ToObservable();
            obsWatchers.SelectMany(
                watcher =>
                    Observable.Timer(watcher.StartTime, TimeSpan.FromHours(watcher.Interval))
                              .SelectMany(
                                    Observable.FromAsync(
                                      async () => new
                                      {
                                          watcher,
                                          response = await CheckFolder(watcher.Path)
                                      })))
                              .Subscribe(
                                    onNext: x =>
                                    {
                                        eventLog.WriteFormattedEntry("\nWatcher: {0}, Time:{1}", x.watcher.Name, DateTimeOffset.Now);
                                        if (x.response.Success)
                                            eventLog.WriteFormattedEntry("| Success!\n| Value: '{0}'\n| Message: {0}", x.response.Value, x.response.Message);
                                        else
                                            eventLog.WriteFormattedEntry("| FAILURE!\n| Value: '{0}'\n| Message: {0}\n| Errors: '{0}'", x.response.Value, x.response.Message, x.response.Exceptions.First());
                                    },
                                    onError: e =>
                                        {
                                            var err = e;
                                            var sb = new StringBuilder();
                                            sb.AppendLine("The observer threw an error:")
                                              .AppendFormatLine("| Message: {0}", e.Message);

                                            while (e.InnerException != null)
                                            {
                                                sb.AppendFormatLine("| Inner: {0}", e.InnerException.Message);
                                                e = e.InnerException;
                                            }

                                            sb.AppendLine();
                                            eventLog.WriteEntry(sb.ToString());
                                            throw err;
                                        });

            eventLog.WriteEntry("about to wait.");
            obsWatchers.Wait();
            eventLog.WriteEntry("passed the wait");
        }
        catch (Exception e)
        {
            eventLog.WriteFormattedEntry("Exception thrown in InitializeWatchers(WatchersSection): {0}", e.Message);
            throw;
        }
    }

When I run this code, the service starts normally. The event log records three events:

  1. Service & Logging started.
  2. Initializing 1 watchers.
  3. Service start completed.

... and it stops. I have to manually refresh the Services window, but it quits running. I don't get any errors, or any of the other eventLog entries.

The frustrating thing is that this code works perfectly as a Console app. I've changed all the eventLog.WriteEntry() to Console.WriteLine(), but other than that, the code is identical and performs as expected.

Any wisdom would be appreciated.

Scott Baker
  • 10,013
  • 17
  • 56
  • 102

2 Answers2

1

I suspect that the Service Control Manager is terminating your service because it did not return from OnStart within the timeout window (30 seconds, IIRC).

I have a blog post on managed service basics, which is based on a blog entry by the BCL team. Note that the MSDN docs are insufficient; you must know the information in the BCL team blog post to correctly write a managed service.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
0

Instead of using obsWatchers.Wait() which blocks and causes the problems Stephen has said, just asynchronously subscribe.

Add this property to your class:

private SingleAssignmentDisposable _subscription = new SingleAssignmentDisposable();

Add this to your OnStop method:

_subscription.Dispose();

In your InitializeWatchers(), eliminate the nested call to Subscribe and replace obsWatchers.Wait() with a call to subscribe, like so:

private void InitializeWatchers()
{
    try
    {

        var watchers = _watcherSection.Watchers.ToList<WatcherElement>();

        eventLog.WriteEntry(string.Format("Initializing {0} watchers.", watchers.Count()));

        var obsWatchers = watchers.ToObservable();
        _subscription.Disposable = obsWatchers
            .SelectMany(watcher => Observable
                .Timer(watcher.StartTime, TimeSpan.FromHours(watcher.Interval))
                .SelectMany(_ => Observable.FromAsync(async () => new
                      {
                          watcher,
                          response = await CheckFolder(watcher.Path)
                      })))
             .Subscribe(
                 onNext: x =>
                 {
                     eventLog.WriteFormattedEntry("\nWatcher: {0}, Time:{1}", x.watcher.Name, DateTimeOffset.Now);
                     if (x.response.Success)
                         eventLog.WriteFormattedEntry("| Success!\n| Value: '{0}'\n| Message: {0}", x.response.Value, x.response.Message);
                     else
                         eventLog.WriteFormattedEntry("| FAILURE!\n| Value: '{0}'\n| Message: {0}\n| Errors: '{0}'", x.response.Value, x.response.Message, x.response.Exceptions.First());
                 },
                 onError: e =>
                 {
                     var err = e;
                     var sb = new StringBuilder();
                     sb.AppendLine("The observer threw an error:")
                       .AppendFormatLine("| Message: {0}", e.Message);

                     while (e.InnerException != null)
                     {
                         sb.AppendFormatLine("| Inner: {0}", e.InnerException.Message);
                         e = e.InnerException;
                     }

                     sb.AppendLine();
                     eventLog.WriteEntry(sb.ToString());
                     throw err;
                 });
        eventLog.WriteEntry("passed the wait");
    }
    catch (Exception e)
    {
        eventLog.WriteFormattedEntry("Exception thrown in InitializeWatchers(WatchersSection): {0}", e.Message);
        throw;
    }
}
Brandon
  • 38,310
  • 8
  • 82
  • 87