Shutdown! Restart working for services

pull/4/head
Mark McDowall 10 years ago
parent 119a4ff39c
commit f69bb79077

@ -13,30 +13,33 @@ namespace NzbDrone.Common.EnvironmentInfo
bool IsUserInteractive { get; }
bool IsAdmin { get; }
bool IsWindowsService { get; }
bool IsConsole { get; }
bool IsRunning { get; set; }
}
public class RuntimeInfo : IRuntimeInfo
{
private readonly Logger _logger;
private static readonly string ProcessName = Process.GetCurrentProcess().ProcessName.ToLower();
public RuntimeInfo(Logger logger, IServiceProvider serviceProvider)
{
_logger = logger;
IsWindowsService = !IsUserInteractive &&
OsInfo.IsWindows &&
serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME) &&
serviceProvider.GetStatus(ServiceProvider.NZBDRONE_SERVICE_NAME) == ServiceControllerStatus.StartPending;
OsInfo.IsWindows &&
serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME) &&
serviceProvider.GetStatus(ServiceProvider.NZBDRONE_SERVICE_NAME) == ServiceControllerStatus.StartPending;
}
public bool IsUserInteractive
static RuntimeInfo()
{
get { return Environment.UserInteractive; }
IsProduction = InternalIsProduction();
}
static RuntimeInfo()
public bool IsUserInteractive
{
IsProduction = InternalIsProduction();
get { return Environment.UserInteractive; }
}
public bool IsAdmin
@ -58,7 +61,18 @@ namespace NzbDrone.Common.EnvironmentInfo
public bool IsWindowsService { get; private set; }
private static readonly string ProcessName = Process.GetCurrentProcess().ProcessName.ToLower();
public bool IsConsole
{
get
{
return (OsInfo.IsWindows &&
IsUserInteractive &&
ProcessName.Equals("NzbDrone.Console.exe", StringComparison.InvariantCultureIgnoreCase)) ||
OsInfo.IsLinux;
}
}
public bool IsRunning { get; set; }
public static bool IsProduction { get; private set; }

@ -5,6 +5,7 @@ using NLog;
using NLog.Config;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes;
namespace NzbDrone.Common.Instrumentation
{
@ -30,7 +31,7 @@ namespace NzbDrone.Common.Instrumentation
}
else
{
if (inConsole && (OsInfo.IsLinux || new RuntimeInfo(null, new ServiceProvider()).IsUserInteractive))
if (inConsole && (OsInfo.IsLinux || new RuntimeInfo(null, new ServiceProvider(new ProcessProvider())).IsUserInteractive))
{
RegisterConsole();
}

@ -6,6 +6,7 @@ using System.Linq;
using System.ServiceProcess;
using NLog;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Common.Processes;
namespace NzbDrone.Common
{
@ -20,14 +21,22 @@ namespace NzbDrone.Common
void Stop(string serviceName);
void Start(string serviceName);
ServiceControllerStatus GetStatus(string serviceName);
void Restart(string serviceName);
}
public class ServiceProvider : IServiceProvider
{
public const string NZBDRONE_SERVICE_NAME = "NzbDrone";
private readonly IProcessProvider _processProvider;
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public ServiceProvider(IProcessProvider processProvider)
{
_processProvider = processProvider;
}
public virtual bool ServiceExist(string name)
{
Logger.Debug("Checking if service {0} exists.", name);
@ -173,5 +182,12 @@ namespace NzbDrone.Common
Logger.Error("Service start request has timed out. {0}", service.Status);
}
}
public void Restart(string serviceName)
{
var args = String.Format("/C net.exe stop \"{0}\" && net.exe start \"{0}\"", serviceName);
_processProvider.Start("cmd.exe", args);
}
}
}

@ -0,0 +1,9 @@
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.Lifecycle
{
public class ApplicationRestartRequested : IEvent
{
}
}

@ -0,0 +1,8 @@
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.Lifecycle.Commands
{
public class RestartCommand : Command
{
}
}

@ -0,0 +1,8 @@
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.Lifecycle.Commands
{
public class ShutdownCommand : Command
{
}
}

@ -0,0 +1,53 @@
using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes;
using NzbDrone.Core.Lifecycle.Commands;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using IServiceProvider = NzbDrone.Common.IServiceProvider;
namespace NzbDrone.Core.Lifecycle
{
public class LifestyleService: IExecute<ShutdownCommand>, IExecute<RestartCommand>
{
private readonly IEventAggregator _eventAggregator;
private readonly IRuntimeInfo _runtimeInfo;
private readonly IServiceProvider _serviceProvider;
private readonly IProcessProvider _processProvider;
public LifestyleService(IEventAggregator eventAggregator,
IRuntimeInfo runtimeInfo,
IServiceProvider serviceProvider,
IProcessProvider processProvider)
{
_eventAggregator = eventAggregator;
_runtimeInfo = runtimeInfo;
_serviceProvider = serviceProvider;
_processProvider = processProvider;
}
public void Execute(ShutdownCommand message)
{
if (_runtimeInfo.IsWindowsService)
{
_serviceProvider.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME);
}
else
{
_eventAggregator.PublishEvent(new ApplicationShutdownRequested());
}
}
public void Execute(RestartCommand message)
{
if (_runtimeInfo.IsWindowsService)
{
_serviceProvider.Restart(ServiceProvider.NZBDRONE_SERVICE_NAME);
}
_eventAggregator.PublishEvent(new ApplicationRestartRequested());
}
}
}

@ -290,6 +290,10 @@
<Compile Include="Instrumentation\Commands\TrimLogCommand.cs" />
<Compile Include="Instrumentation\DeleteLogFilesService.cs" />
<Compile Include="MediaFiles\Commands\RescanSeriesCommand.cs" />
<Compile Include="Lifecycle\Commands\ShutdownCommand.cs" />
<Compile Include="Lifecycle\Commands\RestartCommand.cs" />
<Compile Include="Lifecycle\ApplicationRestartRequested.cs" />
<Compile Include="Lifecycle\LifestyleService.cs" />
<Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" />
<Compile Include="MediaFiles\EpisodeFileMoveResult.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" />

@ -2,18 +2,19 @@
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Host.Owin;
namespace NzbDrone.Host
{
public interface INzbDroneServiceFactory
{
bool IsServiceStopped { get; }
ServiceBase Build();
void Start();
}
public class NzbDroneServiceFactory : ServiceBase, INzbDroneServiceFactory
public class NzbDroneServiceFactory : ServiceBase, INzbDroneServiceFactory, IHandle<ApplicationShutdownRequested>
{
private readonly IConfigFileProvider _configFileProvider;
private readonly IRuntimeInfo _runtimeInfo;
@ -42,6 +43,7 @@ namespace NzbDrone.Host
public void Start()
{
_runtimeInfo.IsRunning = true;
_hostController.StartServer();
if (!_startupContext.Flags.Contains(StartupContext.NO_BROWSER)
@ -54,19 +56,29 @@ namespace NzbDrone.Host
}
protected override void OnStop()
{
Shutdown();
}
public ServiceBase Build()
{
return this;
}
private void Shutdown()
{
_logger.Info("Attempting to stop application.");
_hostController.StopServer();
_logger.Info("Application has finished stop routine.");
IsServiceStopped = true;
_runtimeInfo.IsRunning = false;
}
public bool IsServiceStopped { get; private set; }
public ServiceBase Build()
public void Handle(ApplicationShutdownRequested message)
{
return this;
if (!_runtimeInfo.IsWindowsService)
{
Shutdown();
}
}
}
}

@ -72,9 +72,9 @@ namespace NzbDrone.Host
return;
}
var serviceFactory = _container.Resolve<INzbDroneServiceFactory>();
var runTimeInfo = _container.Resolve<IRuntimeInfo>();
while (!serviceFactory.IsServiceStopped)
while (runTimeInfo.IsRunning)
{
Thread.Sleep(1000);
}

@ -68,7 +68,15 @@ namespace NzbDrone.SysTray
_trayIcon.Dispose();
}
base.Dispose(isDisposing);
if (InvokeRequired)
{
base.Invoke(new MethodInvoker(() => Dispose(isDisposing)));
}
else
{
base.Dispose(isDisposing);
}
}
private void OnExit(object sender, EventArgs e)

Loading…
Cancel
Save