From 99ab61fac667f02791d440178039f18731498676 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 28 Oct 2017 23:49:54 -0400 Subject: [PATCH] Fixed: Slower daemon startup loop if Lidarr runs into non-recoverable errors --- .../EnvironmentInfo/AppFolderFactory.cs | 6 ++ .../Exceptions/LidarrStartupException.cs | 44 ++++++++++++ src/NzbDrone.Common/NzbDrone.Common.csproj | 1 + .../Processes/PidFileProvider.cs | 3 +- src/NzbDrone.Console/ConsoleApp.cs | 68 +++++++++++++++---- src/NzbDrone.Host/Bootstrap.cs | 10 ++- 6 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 src/NzbDrone.Common/Exceptions/LidarrStartupException.cs diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs index bf7c43a7d..0b13dadc4 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs @@ -3,6 +3,7 @@ using System.Security.AccessControl; using System.Security.Principal; using NLog; using NzbDrone.Common.Disk; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; namespace NzbDrone.Common.EnvironmentInfo @@ -36,6 +37,11 @@ namespace NzbDrone.Common.EnvironmentInfo { SetPermissions(); } + + if (!_diskProvider.FolderWritable(_appFolderInfo.AppDataFolder)) + { + throw new LidarrStartupException("AppFolder {0} is not writable", _appFolderInfo.AppDataFolder); + } } private void SetPermissions() diff --git a/src/NzbDrone.Common/Exceptions/LidarrStartupException.cs b/src/NzbDrone.Common/Exceptions/LidarrStartupException.cs new file mode 100644 index 000000000..64e04de71 --- /dev/null +++ b/src/NzbDrone.Common/Exceptions/LidarrStartupException.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Common.Exceptions +{ + public class LidarrStartupException : NzbDroneException + { + public LidarrStartupException(string message, params object[] args) + : base("Lidarr failed to start: " + string.Format(message, args)) + { + + } + + public LidarrStartupException(string message) + : base("Lidarr failed to start: " + message) + { + + } + + public LidarrStartupException() + : base("Lidarr failed to start") + { + + } + + public LidarrStartupException(Exception innerException, string message, params object[] args) + : base("Lidarr failed to start: " + string.Format(message, args), innerException) + { + } + + public LidarrStartupException(Exception innerException, string message) + : base("Lidarr failed to start: " + message, innerException) + { + } + + public LidarrStartupException(Exception innerException) + : base("Lidarr failed to start: " + innerException.Message) + { + + } + } +} diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj index 5606b2045..d8a4a0917 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -96,6 +96,7 @@ + diff --git a/src/NzbDrone.Common/Processes/PidFileProvider.cs b/src/NzbDrone.Common/Processes/PidFileProvider.cs index 796c0a41d..a272b1c7b 100644 --- a/src/NzbDrone.Common/Processes/PidFileProvider.cs +++ b/src/NzbDrone.Common/Processes/PidFileProvider.cs @@ -2,6 +2,7 @@ using System; using System.IO; using NLog; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; namespace NzbDrone.Common.Processes { @@ -38,7 +39,7 @@ namespace NzbDrone.Common.Processes catch (Exception ex) { _logger.Error(ex, "Unable to write PID file {0}", filename); - throw; + throw new LidarrStartupException(ex, "Unable to write PID file {0}", filename); } } } diff --git a/src/NzbDrone.Console/ConsoleApp.cs b/src/NzbDrone.Console/ConsoleApp.cs index f15eb1b56..385991765 100644 --- a/src/NzbDrone.Console/ConsoleApp.cs +++ b/src/NzbDrone.Console/ConsoleApp.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Net.Sockets; using NLog; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Host; @@ -11,6 +12,14 @@ namespace NzbDrone.Console { private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(ConsoleApp)); + private enum ExitCodes : int + { + Normal = 0, + UnknownFailure = 1, + RecoverableFailure = 2, + NonRecoverableFailure = 3 + } + public static void Main(string[] args) { try @@ -19,30 +28,61 @@ namespace NzbDrone.Console NzbDroneLogger.Register(startupArgs, false, true); Bootstrap.Start(startupArgs, new ConsoleAlerts()); } - catch (SocketException exception) + catch (LidarrStartupException ex) { System.Console.WriteLine(""); System.Console.WriteLine(""); - Logger.Fatal(exception.Message + ". This can happen if another instance of Lidarr is already running another application is using the same port (default: 8686) or the user has insufficient permissions"); - System.Console.WriteLine("Press enter to exit..."); - System.Console.ReadLine(); - Environment.Exit(1); + Logger.Fatal(ex, "EPIC FAIL!"); + Exit(ExitCodes.NonRecoverableFailure); } - catch (Exception e) + catch (SocketException ex) { System.Console.WriteLine(""); System.Console.WriteLine(""); - Logger.Fatal(e, "EPIC FAIL!"); - System.Console.WriteLine("Press enter to exit..."); - System.Console.ReadLine(); - Environment.Exit(1); + Logger.Fatal(ex.Message + ". This can happen if another instance of Sonarr is already running another application is using the same port (default: 8989) or the user has insufficient permissions"); + Exit(ExitCodes.RecoverableFailure); + } + catch (Exception ex) + { + System.Console.WriteLine(""); + System.Console.WriteLine(""); + Logger.Fatal(ex, "EPIC FAIL!"); + Exit(ExitCodes.UnknownFailure); } Logger.Info("Exiting main."); - //Need this to terminate on mono (thanks nlog) - LogManager.Configuration = null; - Environment.Exit(0); + Exit(ExitCodes.Normal); + } + + private static void Exit(ExitCodes exitCode) + { + LogManager.Flush(); + + if (exitCode != ExitCodes.Normal) + { + System.Console.WriteLine("Press enter to exit..."); + + System.Threading.Thread.Sleep(1000); + + if (exitCode == ExitCodes.NonRecoverableFailure) + { + System.Console.WriteLine("Non-recoverable failure, waiting for user intervention..."); + for (int i = 0; i< 3600; i++) + { + System.Threading.Thread.Sleep(1000); + + if (System.Console.KeyAvailable) break; + } + } + + // Please note that ReadLine silently succeeds if there is no console, KeyAvailable does not. + System.Console.ReadLine(); + } + + //Need this to terminate on mono (thanks nlog) + LogManager.Configuration = null; + Environment.Exit((int)exitCode); } } } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 77c55bcc9..9062c2d98 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -4,9 +4,11 @@ using System.Threading; using NLog; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Exceptions; using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Processes; using NzbDrone.Common.Security; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Datastore; using NzbDrone.Core.Instrumentation; @@ -49,9 +51,13 @@ namespace NzbDrone.Host SpinToExit(appMode); } } - catch (TerminateApplicationException e) + catch (InvalidConfigFileException ex) { - Logger.Info(e.Message); + throw new LidarrStartupException(ex); + } + catch (TerminateApplicationException ex) + { + Logger.Info(ex.Message); LogManager.Configuration = null; } }