Skip to content

Commit

Permalink
Exposed the ability to attach a custom exception handler
Browse files Browse the repository at this point in the history
This provides a way for clients using Topshelf to act upon any exceptions that are thrown within the service (including unhandled exceptions).
  • Loading branch information
Sam Storie authored and TravisTheTechie committed Aug 19, 2016
1 parent 52ae2d7 commit 16bf506
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/SampleTopshelfService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ static int Main()
x.AddCommandLineSwitch("throwonstart", v => throwOnStart = v);
x.AddCommandLineSwitch("throwonstop", v => throwOnStop = v);
x.AddCommandLineSwitch("throwunhandled", v => throwUnhandled = v);

x.AddExceptionHandler(ex =>
{
Console.WriteLine("Exception thrown - " + ex.Message);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,12 @@ public interface HostConfigurator
/// <param name="name"></param>
/// <param name="callback"></param>
void AddCommandLineDefinition(string name, Action<string> callback);

/// <summary>
/// Adds custom exception handler that will be called for any exception caught
/// by Topshelf while a service is starting, running or stopping.
/// </summary>
/// <param name="callback"></param>
void AddExceptionHandler(Action<Exception> callback);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ public void AddCommandLineDefinition(string name, Action<string> callback)
_commandLineOptionConfigurators.Add(configurator);
}

public void AddExceptionHandler(Action<Exception> callback)
{
_settings.ExceptionHandler = callback;
}

public Host CreateHost()
{
Type type = typeof(HostFactory);
Expand Down
12 changes: 12 additions & 0 deletions src/Topshelf/Hosts/ConsoleRunHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ public TopshelfExitCode Run()
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Error("An exception occurred", ex);

return TopshelfExitCode.AbnormalExit;
Expand Down Expand Up @@ -144,6 +148,10 @@ void HostControl.Restart()

void CatchUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke((Exception)e.ExceptionObject);

_log.Fatal("The service threw an unhandled exception", (Exception)e.ExceptionObject);

HostLogger.Shutdown();
Expand Down Expand Up @@ -185,6 +193,10 @@ void StopService()
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Error("The service did not shut down gracefully", ex);
}
finally
Expand Down
5 changes: 5 additions & 0 deletions src/Topshelf/Hosts/InstallHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ public TimeSpan StopTimeOut
{
get { return _settings.StopTimeOut; }
}

public Action<Exception> ExceptionHandler
{
get { return _settings.ExceptionHandler; }
}
}
}
}
5 changes: 5 additions & 0 deletions src/Topshelf/Runtime/HostSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,10 @@ public interface HostSettings
/// The amount of time to wait for the service to stop before timing out. Default is 10 seconds.
/// </summary>
TimeSpan StopTimeOut { get; }

/// <summary>
/// A callback to provide additional exception handling beyond what is already provided
/// </summary>
Action<Exception> ExceptionHandler { get; }
}
}
2 changes: 2 additions & 0 deletions src/Topshelf/Runtime/Windows/WindowsHostSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,7 @@ public string ServiceName
public TimeSpan StartTimeOut { get; set; }

public TimeSpan StopTimeOut { get; set; }

public Action<Exception> ExceptionHandler { get; set; }
}
}
32 changes: 32 additions & 0 deletions src/Topshelf/Runtime/Windows/WindowsServiceHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ protected override void OnStart(string[] args)
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Fatal("The service did not start successfully", ex);

ExitCode = (int)TopshelfExitCode.StartServiceFailed;
Expand All @@ -150,6 +154,10 @@ protected override void OnStop()
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Fatal("The service did not shut down gracefully", ex);
ExitCode = (int)TopshelfExitCode.StopServiceFailed;
throw;
Expand All @@ -176,6 +184,10 @@ protected override void OnPause()
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Fatal("The service did not pause gracefully", ex);
throw;
}
Expand All @@ -194,6 +206,10 @@ protected override void OnContinue()
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Fatal("The service did not resume successfully", ex);
throw;
}
Expand All @@ -211,6 +227,10 @@ protected override void OnShutdown()
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Fatal("The service did not shut down gracefully", ex);
ExitCode = (int)TopshelfExitCode.StopServiceFailed;
throw;
Expand All @@ -231,6 +251,10 @@ protected override void OnSessionChange(SessionChangeDescription changeDescripti
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Fatal("The service did not shut down gracefully", ex);
ExitCode = (int)TopshelfExitCode.StopServiceFailed;
throw;
Expand All @@ -249,6 +273,10 @@ protected override void OnCustomCommand(int command)
}
catch (Exception ex)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke(ex);

_log.Error("Unhandled exception during custom command processing detected", ex);
}
}
Expand All @@ -268,6 +296,10 @@ protected override void Dispose(bool disposing)

void CatchUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// Call the custom exception handler if it is not null
//
_settings.ExceptionHandler?.Invoke((Exception)e.ExceptionObject);

_log.Fatal("The service threw an unhandled exception", (Exception)e.ExceptionObject);

HostLogger.Shutdown();
Expand Down

0 comments on commit 16bf506

Please sign in to comment.