2016-08-25 15:09:51 +02:00
using System ;
2020-11-19 20:05:28 +00:00
using Microsoft.Extensions.Logging ;
2017-05-30 15:46:25 +02:00
using Umbraco.Core.Composing ;
2019-11-20 13:38:41 +01:00
using Umbraco.Core.Hosting ;
2016-08-25 15:09:51 +02:00
using Umbraco.Core.Logging ;
2020-11-19 20:05:28 +00:00
using Umbraco.Core.Persistence ;
2016-08-25 15:09:51 +02:00
2017-12-28 09:27:57 +01:00
namespace Umbraco.Core.Runtime
2016-08-25 15:09:51 +02:00
{
public class CoreRuntime : IRuntime
{
2020-11-10 08:50:47 +00:00
public IRuntimeState State { get ; }
2016-08-25 15:09:51 +02:00
2020-11-19 20:05:28 +00:00
private readonly ILogger < CoreRuntime > _logger ;
2020-11-10 08:50:47 +00:00
private readonly ComponentCollection _components ;
private readonly IApplicationShutdownRegistry _applicationShutdownRegistry ;
private readonly IProfilingLogger _profilingLogger ;
private readonly IMainDom _mainDom ;
2020-11-19 20:05:28 +00:00
private readonly IUmbracoDatabaseFactory _databaseFactory ;
2020-10-27 10:53:01 +00:00
2019-12-12 12:55:17 +01:00
public CoreRuntime (
2020-11-19 20:05:28 +00:00
ILogger < CoreRuntime > logger ,
2020-11-10 08:50:47 +00:00
IRuntimeState state ,
ComponentCollection components ,
IApplicationShutdownRegistry applicationShutdownRegistry ,
IProfilingLogger profilingLogger ,
2020-11-19 20:05:28 +00:00
IMainDom mainDom ,
IUmbracoDatabaseFactory databaseFactory )
2019-11-15 11:07:37 +01:00
{
2020-11-10 08:50:47 +00:00
State = state ;
2020-11-19 20:05:28 +00:00
_logger = logger ;
2020-11-10 08:50:47 +00:00
_components = components ;
_applicationShutdownRegistry = applicationShutdownRegistry ;
_profilingLogger = profilingLogger ;
_mainDom = mainDom ;
2020-11-19 20:05:28 +00:00
_databaseFactory = databaseFactory ;
2019-11-15 11:07:37 +01:00
}
2020-11-10 08:50:47 +00:00
2019-11-15 11:07:37 +01:00
2020-11-10 08:50:47 +00:00
public void Start ( )
2016-08-25 15:09:51 +02:00
{
2020-11-23 12:04:40 +00:00
AppDomain . CurrentDomain . UnhandledException + = ( _ , args ) = >
{
var exception = ( Exception ) args . ExceptionObject ;
var isTerminating = args . IsTerminating ; // always true?
var msg = "Unhandled exception in AppDomain" ;
if ( isTerminating ) msg + = " (terminating)" ;
msg + = "." ;
_logger . LogError ( exception , msg ) ;
} ;
2020-11-19 20:05:28 +00:00
DetermineRuntimeLevel ( ) ;
2020-11-10 08:50:47 +00:00
if ( State . Level < = RuntimeLevel . BootFailed )
2020-05-08 17:30:30 +10:00
throw new InvalidOperationException ( $"Cannot start the runtime if the runtime level is less than or equal to {RuntimeLevel.BootFailed}" ) ;
2020-11-10 08:50:47 +00:00
var hostingEnvironmentLifetime = _applicationShutdownRegistry ;
2020-03-25 15:06:22 +11:00
if ( hostingEnvironmentLifetime = = null )
2020-03-26 15:39:20 +11:00
throw new InvalidOperationException ( $"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(Start)}" ) ;
2020-03-25 15:06:22 +11:00
// acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
2020-11-10 08:50:47 +00:00
AcquireMainDom ( _mainDom , _applicationShutdownRegistry ) ;
2020-03-25 15:06:22 +11:00
// create & initialize the components
_components . Initialize ( ) ;
2016-09-11 19:57:33 +02:00
}
2016-09-01 19:06:08 +02:00
2020-11-10 08:50:47 +00:00
public void Terminate ( )
2016-09-11 19:57:33 +02:00
{
2020-11-10 08:50:47 +00:00
_components ? . Terminate ( ) ;
2016-09-11 19:57:33 +02:00
}
2016-09-01 19:06:08 +02:00
2020-11-10 08:50:47 +00:00
private void AcquireMainDom ( IMainDom mainDom , IApplicationShutdownRegistry applicationShutdownRegistry )
2016-09-11 19:57:33 +02:00
{
2020-11-10 08:50:47 +00:00
using ( var timer = _profilingLogger . DebugDuration < CoreRuntime > ( "Acquiring MainDom." , "Acquired." ) )
2016-09-11 19:57:33 +02:00
{
try
{
2020-11-10 08:50:47 +00:00
mainDom . Acquire ( applicationShutdownRegistry ) ;
2016-09-11 19:57:33 +02:00
}
catch
{
2019-02-05 20:01:20 +01:00
timer ? . Fail ( ) ;
2016-09-11 19:57:33 +02:00
throw ;
}
2016-09-01 19:06:08 +02:00
}
2016-08-25 15:09:51 +02:00
}
2020-11-19 20:05:28 +00:00
private void DetermineRuntimeLevel ( )
{
using var timer = _profilingLogger . DebugDuration < CoreRuntime > ( "Determining runtime level." , "Determined." ) ;
try
{
State . DetermineRuntimeLevel ( ) ;
_logger . LogDebug ( "Runtime level: {RuntimeLevel} - {RuntimeLevelReason}" , State . Level , State . Reason ) ;
if ( State . Level = = RuntimeLevel . Upgrade )
{
_logger . LogDebug ( "Configure database factory for upgrades." ) ;
_databaseFactory . ConfigureForUpgrade ( ) ;
}
}
catch
{
// BOO a cast, yay no CoreRuntimeBootstrapper
( ( RuntimeState ) State ) . Level = RuntimeLevel . BootFailed ;
( ( RuntimeState ) State ) . Reason = RuntimeLevelReason . BootFailedOnException ;
timer ? . Fail ( ) ;
throw ;
}
}
2016-08-25 15:09:51 +02:00
}
}