From 431d066300b11eac002eb716c0d7a7388058da4d Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 9 Jul 2015 14:31:59 +0200 Subject: [PATCH] Changes the ApplicationEventHandler to check if the db is configured instead of being connected to which can cause issues if SQLCE file is locked by another app domain on startup. Then we verify in the CoreBootManager that the db can be connected to with a retry policy. Changes the db context CanConnect method to not store a static value since it might later be able to be connected to. --- src/Umbraco.Core/ApplicationEventHandler.cs | 4 +-- src/Umbraco.Core/CoreBootManager.cs | 31 +++++++++++++++++++ src/Umbraco.Core/DatabaseContext.cs | 20 ++---------- .../UmbracoStartupFailedException.cs | 18 +++++++++++ src/Umbraco.Core/TypeFinder.cs | 6 +++- src/Umbraco.Core/Umbraco.Core.csproj | 1 + 6 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 src/Umbraco.Core/Exceptions/UmbracoStartupFailedException.cs diff --git a/src/Umbraco.Core/ApplicationEventHandler.cs b/src/Umbraco.Core/ApplicationEventHandler.cs index a725a08a8e..8d97baac95 100644 --- a/src/Umbraco.Core/ApplicationEventHandler.cs +++ b/src/Umbraco.Core/ApplicationEventHandler.cs @@ -74,7 +74,7 @@ namespace Umbraco.Core /// private bool ShouldExecute(ApplicationContext applicationContext) { - if (applicationContext.IsConfigured && applicationContext.DatabaseContext.CanConnect) + if (applicationContext.IsConfigured && applicationContext.DatabaseContext.IsDatabaseConfigured) { return true; } @@ -84,7 +84,7 @@ namespace Umbraco.Core return true; } - if (!applicationContext.DatabaseContext.CanConnect && ExecuteWhenDatabaseNotConfigured) + if (!applicationContext.DatabaseContext.IsDatabaseConfigured && ExecuteWhenDatabaseNotConfigured) { return true; } diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index f5dbdcf957..c5d3e2a4c7 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using System.Web; using AutoMapper; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Exceptions; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models.Mapping; @@ -261,6 +263,9 @@ namespace Umbraco.Core FreezeResolution(); + //Here we need to make sure the db can be connected to + EnsureDatabaseConnection(); + using (DisposableTimer.DebugDuration( () => string.Format("Executing {0} IApplicationEventHandler.OnApplicationStarted", ApplicationEventsResolver.Current.ApplicationEventHandlers.Count()), () => "Finished executing IApplicationEventHandler.OnApplicationStarted")) @@ -299,6 +304,32 @@ namespace Umbraco.Core return this; } + /// + /// We cannot continue if the db cannot be connected to + /// + private void EnsureDatabaseConnection() + { + if (ApplicationContext.IsConfigured == false) return; + if (ApplicationContext.DatabaseContext.IsDatabaseConfigured == false) return; + + var currentTry = 0; + while (currentTry < 5) + { + if (ApplicationContext.DatabaseContext.CanConnect) + break; + + //wait and retry + Thread.Sleep(1000); + currentTry++; + } + + if (currentTry == 5) + { + throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but the Umbraco cannot connect to the database."); + } + + } + /// /// Freeze resolution to not allow Resolvers to be modified /// diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs index fad96b849d..dfaebb0315 100644 --- a/src/Umbraco.Core/DatabaseContext.cs +++ b/src/Umbraco.Core/DatabaseContext.cs @@ -26,8 +26,6 @@ namespace Umbraco.Core { private readonly IDatabaseFactory _factory; private bool _configured; - private bool _canConnect; - private volatile bool _connectCheck = false; private readonly object _locker = new object(); private string _connectionString; private string _providerName; @@ -67,21 +65,9 @@ namespace Umbraco.Core get { if (IsDatabaseConfigured == false) return false; - - //double check lock so that it is only checked once and is fast - if (_connectCheck == false) - { - lock (_locker) - { - if (_canConnect == false) - { - _canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider); - _connectCheck = true; - } - } - } - - return _canConnect; + var canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider); + LogHelper.Info("CanConnect = " + canConnect); + return canConnect; } } diff --git a/src/Umbraco.Core/Exceptions/UmbracoStartupFailedException.cs b/src/Umbraco.Core/Exceptions/UmbracoStartupFailedException.cs new file mode 100644 index 0000000000..d27d38de9a --- /dev/null +++ b/src/Umbraco.Core/Exceptions/UmbracoStartupFailedException.cs @@ -0,0 +1,18 @@ +using System; + +namespace Umbraco.Core.Exceptions +{ + /// + /// An exception that is thrown if the umbraco application cannnot boot + /// + public class UmbracoStartupFailedException : Exception + { + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + public UmbracoStartupFailedException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/TypeFinder.cs b/src/Umbraco.Core/TypeFinder.cs index 962f0e3d91..abaf5ae5e0 100644 --- a/src/Umbraco.Core/TypeFinder.cs +++ b/src/Umbraco.Core/TypeFinder.cs @@ -700,7 +700,11 @@ namespace Umbraco.Core #endregion - public static Type GetTypeByName(string typeName) + //TODO: This isn't very elegant, and will have issues since the AppDomain.CurrentDomain + // doesn't actualy load in all assemblies, only the types that have been referenced so far. + // However, in a web context, the BuildManager will have executed which will force all assemblies + // to be loaded so it's fine for now. + internal static Type GetTypeByName(string typeName) { var type = Type.GetType(typeName); if (type != null) return type; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 67ce55b8f1..4e155e1b3d 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -312,6 +312,7 @@ +