From d42a63a480e1757592b8efa64dc7f2f771ffa1bd Mon Sep 17 00:00:00 2001 From: kayone Date: Mon, 25 Nov 2013 23:08:12 -0800 Subject: [PATCH] Service kills other instances on start. --- .../NzbDroneProcessServiceFixture.cs | 6 +-- src/NzbDrone.Common/ConsoleService.cs | 6 +-- .../Processes/ProcessProvider.cs | 3 +- src/NzbDrone.Host/Bootstrap.cs | 17 +++++++-- src/NzbDrone.Host/NzbDroneProcessService.cs | 37 +++++++++++++++---- .../TerminateApplicationException.cs | 4 +- 6 files changed, 51 insertions(+), 22 deletions(-) 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 @@ namespace NzbDrone.App.Test }); - Subject.EnforceSingleInstance(); + Subject.PreventStartIfAlreadyRunning(); Mocker.GetMock().Verify(c => c.LaunchWebUI(), Times.Never()); @@ -59,7 +59,7 @@ namespace NzbDrone.App.Test - Assert.Throws(() => Subject.EnforceSingleInstance()); + Assert.Throws(() => Subject.PreventStartIfAlreadyRunning()); Mocker.GetMock().Verify(c => c.LaunchWebUI(), Times.Once()); ExceptionVerification.ExpectedWarns(1); } @@ -83,7 +83,7 @@ namespace NzbDrone.App.Test - 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 @@ namespace NzbDrone.Common 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 @@ namespace NzbDrone.Common.Processes 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 @@ namespace NzbDrone.Common.Processes 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 @@ namespace NzbDrone.Host } catch (TerminateApplicationException e) { - Logger.Info("Application has been terminated. Reason " + e.Reason); + Logger.Info(e.Message); } } @@ -56,7 +56,7 @@ namespace NzbDrone.Host { if (!IsInUtilityMode(applicationModes)) { - EnsureSingleInstance(); + EnsureSingleInstance(applicationModes == ApplicationModes.Service); } DbFactory.RegisterDatabase(_container); @@ -78,9 +78,18 @@ namespace NzbDrone.Host } } - 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 @@ namespace NzbDrone.Host _logger = logger; } - public void EnforceSingleInstance() + public void PreventStartIfAlreadyRunning() { if (IsAlreadyRunning()) { @@ -32,16 +35,34 @@ namespace NzbDrone.Host } } + public void KillAllOtherInstance() + { + 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 guiIds = _processProvider.FindProcessByName(ProcessProvider.NZB_DRONE_PROCESS_NAME).Select(c => c.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(guiIds).Except(new[] { currentId }); + var otherProcesses = consoleIds.Union(winformIds).Except(new[] { currentId }).ToList(); - return otherProcesses.Any(); - } + 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