diff --git a/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs b/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs index e204713fb..0c792f0c3 100644 --- a/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs +++ b/src/NzbDrone.App.Test/NzbDroneProcessServiceFixture.cs @@ -34,7 +34,7 @@ public void should_continue_if_only_instance() }); - Subject.EnforceSingleInstance(); + Subject.PreventStartIfAlreadyRunning(); Mocker.GetMock().Verify(c => c.LaunchWebUI(), Times.Never()); @@ -59,7 +59,7 @@ public void should_enforce_if_another_console_is_running() - Assert.Throws(() => Subject.EnforceSingleInstance()); + Assert.Throws(() => Subject.PreventStartIfAlreadyRunning()); Mocker.GetMock().Verify(c => c.LaunchWebUI(), Times.Once()); ExceptionVerification.ExpectedWarns(1); } @@ -83,7 +83,7 @@ public void should_return_false_if_another_gui_is_running() - Assert.Throws(() => Subject.EnforceSingleInstance()); + Assert.Throws(() => Subject.PreventStartIfAlreadyRunning()); Mocker.GetMock().Verify(c => c.LaunchWebUI(), Times.Once()); ExceptionVerification.ExpectedWarns(1); } diff --git a/src/NzbDrone.Common/ConsoleService.cs b/src/NzbDrone.Common/ConsoleService.cs index cceeade42..9a4caad90 100644 --- a/src/NzbDrone.Common/ConsoleService.cs +++ b/src/NzbDrone.Common/ConsoleService.cs @@ -24,9 +24,9 @@ public void PrintHelp() Console.WriteLine(); Console.WriteLine(" Usage: {0} ", Process.GetCurrentProcess().MainModule.ModuleName); Console.WriteLine(" Commands:"); - Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupArguments.INSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME); - Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupArguments.UNINSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME); - Console.WriteLine(" /{0} Don't open NzbDrone in a browser", StartupArguments.NO_BROWSER); + Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME); + Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME); + Console.WriteLine(" /{0} Don't open NzbDrone in a browser", StartupContext.NO_BROWSER); Console.WriteLine(" Run application in console mode."); } diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs index 30e120828..785b029e5 100644 --- a/src/NzbDrone.Common/Processes/ProcessProvider.cs +++ b/src/NzbDrone.Common/Processes/ProcessProvider.cs @@ -20,6 +20,7 @@ public interface IProcessProvider void WaitForExit(Process process); void SetPriority(int processId, ProcessPriorityClass priority); void KillAll(string processName); + void Kill(int processId); bool Exists(string processName); ProcessPriorityClass GetCurrentProcessPriority(); Process Start(string path, string args = null, Action onOutputDataReceived = null, Action onErrorDataReceived = null); @@ -254,7 +255,7 @@ private static string GetExeFileName(Process process) return process.Modules.Cast().FirstOrDefault(module => module.ModuleName.ToLower().EndsWith(".exe")).FileName; } - private void Kill(int processId) + public void Kill(int processId) { var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId); diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index a11a848ec..952e9c17e 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -47,7 +47,7 @@ public static void Start(StartupContext startupContext, IUserAlert userAlert, Ac } catch (TerminateApplicationException e) { - Logger.Info("Application has been terminated. Reason " + e.Reason); + Logger.Info(e.Message); } } @@ -56,7 +56,7 @@ private static void Start(ApplicationModes applicationModes) { if (!IsInUtilityMode(applicationModes)) { - EnsureSingleInstance(); + EnsureSingleInstance(applicationModes == ApplicationModes.Service); } DbFactory.RegisterDatabase(_container); @@ -78,9 +78,18 @@ private static void SpinToExit(ApplicationModes applicationModes) } } - private static void EnsureSingleInstance() + private static void EnsureSingleInstance(bool isService) { - _container.Resolve().EnforceSingleInstance(); + var instancePolicy = _container.Resolve(); + + if (isService) + { + instancePolicy.KillAllOtherInstance(); + } + else + { + instancePolicy.PreventStartIfAlreadyRunning(); + } } diff --git a/src/NzbDrone.Host/NzbDroneProcessService.cs b/src/NzbDrone.Host/NzbDroneProcessService.cs index 3ee601f84..c13a46f5b 100644 --- a/src/NzbDrone.Host/NzbDroneProcessService.cs +++ b/src/NzbDrone.Host/NzbDroneProcessService.cs @@ -1,4 +1,6 @@ -using System.Linq; +using System; +using System.Collections.Generic; +using System.Linq; using NLog; using NzbDrone.Common.Processes; @@ -6,7 +8,8 @@ namespace NzbDrone.Host { public interface ISingleInstancePolicy { - void EnforceSingleInstance(); + void PreventStartIfAlreadyRunning(); + void KillAllOtherInstance(); } public class SingleInstancePolicy : ISingleInstancePolicy @@ -22,7 +25,7 @@ public SingleInstancePolicy(IProcessProvider processProvider, IBrowserService br _logger = logger; } - public void EnforceSingleInstance() + public void PreventStartIfAlreadyRunning() { if (IsAlreadyRunning()) { @@ -32,16 +35,34 @@ public void EnforceSingleInstance() } } - private bool IsAlreadyRunning() + public void KillAllOtherInstance() { - var currentId = _processProvider.GetCurrentProcess().Id; - var consoleIds = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME).Select(c => c.Id); - var guiIds = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME).Select(c => c.Id); - - var otherProcesses = consoleIds.Union(guiIds).Except(new[] { currentId }); - - return otherProcesses.Any(); + foreach (var processId in GetOtherNzbDroneProcessIds()) + { + _processProvider.Kill(processId); + } } + private bool IsAlreadyRunning() + { + return GetOtherNzbDroneProcessIds().Any(); + } + + private List GetOtherNzbDroneProcessIds() + { + var currentId = _processProvider.GetCurrentProcess().Id; + var consoleIds = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME) + .Select(c => c.Id); + var winformIds = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME).Select(c => c.Id); + + var otherProcesses = consoleIds.Union(winformIds).Except(new[] { currentId }).ToList(); + + if (otherProcesses.Any()) + { + _logger.Info("{0} instance(s) of NzbDrone are running", otherProcesses.Count); + } + + return otherProcesses; + } } } \ No newline at end of file diff --git a/src/NzbDrone.Host/TerminateApplicationException.cs b/src/NzbDrone.Host/TerminateApplicationException.cs index ad703ca18..734fb65d2 100644 --- a/src/NzbDrone.Host/TerminateApplicationException.cs +++ b/src/NzbDrone.Host/TerminateApplicationException.cs @@ -5,10 +5,8 @@ namespace NzbDrone.Host public class TerminateApplicationException : ApplicationException { public TerminateApplicationException(string reason) + : base("Application is being terminated. Reason : " + reason) { - Reason = reason; } - - public string Reason { get; private set; } } } \ No newline at end of file