2020-12-15 15:20:36 +00:00
using System ;
using System.Threading ;
using System.Threading.Tasks ;
2020-11-19 20:05:28 +00:00
using Microsoft.Extensions.Logging ;
2021-02-09 10:22:42 +01:00
using Umbraco.Cms.Core ;
using Umbraco.Cms.Core.Composing ;
using Umbraco.Cms.Core.Events ;
using Umbraco.Cms.Core.Hosting ;
using Umbraco.Cms.Core.Logging ;
using Umbraco.Cms.Core.Runtime ;
using Umbraco.Cms.Core.Services ;
2021-02-12 13:36:50 +01:00
using Umbraco.Cms.Infrastructure.Persistence ;
2021-03-05 17:13:09 +00:00
using Constants = Umbraco . Cms . Core . Constants ;
2016-08-25 15:09:51 +02:00
2021-02-15 11:04:19 +01:00
namespace Umbraco.Cms.Infrastructure.Runtime
2016-08-25 15:09:51 +02:00
{
public class CoreRuntime : IRuntime
{
2020-11-19 20:05:28 +00:00
private readonly ILogger < CoreRuntime > _logger ;
2020-12-15 15:20:36 +00:00
private readonly ILoggerFactory _loggerFactory ;
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-12-15 15:20:36 +00:00
private readonly IEventAggregator _eventAggregator ;
private readonly IHostingEnvironment _hostingEnvironment ;
2020-10-27 10:53:01 +00:00
2020-12-22 12:33:00 +11:00
/// <summary>
/// Initializes a new instance of the <see cref="CoreRuntime"/> class.
/// </summary>
2019-12-12 12:55:17 +01:00
public CoreRuntime (
2020-12-15 15:20:36 +00:00
ILoggerFactory loggerFactory ,
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 ,
2020-12-15 15:20:36 +00:00
IUmbracoDatabaseFactory databaseFactory ,
IEventAggregator eventAggregator ,
2021-03-05 17:13:09 +00:00
IHostingEnvironment hostingEnvironment )
2019-11-15 11:07:37 +01:00
{
2020-11-10 08:50:47 +00:00
State = state ;
2020-12-15 15:20:36 +00:00
_loggerFactory = loggerFactory ;
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 ;
2020-12-15 15:20:36 +00:00
_eventAggregator = eventAggregator ;
_hostingEnvironment = hostingEnvironment ;
_logger = _loggerFactory . CreateLogger < CoreRuntime > ( ) ;
2019-11-15 11:07:37 +01:00
}
2020-12-15 15:20:36 +00:00
/// <summary>
/// Gets the state of the Umbraco runtime.
/// </summary>
public IRuntimeState State { get ; }
/// <inheritdoc/>
public async Task StartAsync ( CancellationToken cancellationToken )
2016-08-25 15:09:51 +02:00
{
2020-12-15 15:20:36 +00:00
StaticApplicationLogging . Initialize ( _loggerFactory ) ;
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" ;
2020-12-15 15:20:36 +00:00
if ( isTerminating )
{
msg + = " (terminating)" ;
}
2020-11-23 12:04:40 +00:00
msg + = "." ;
2020-12-15 15:20:36 +00:00
2020-11-23 12:04:40 +00:00
_logger . LogError ( exception , msg ) ;
} ;
2021-02-09 10:22:42 +01:00
AppDomain . CurrentDomain . SetData ( "DataDirectory" , _hostingEnvironment ? . MapPathContentRoot ( Constants . SystemDirectories . Data ) ) ;
2020-12-15 15:20:36 +00:00
2021-01-18 15:40:22 +01:00
DoUnattendedInstall ( ) ;
2020-11-19 20:05:28 +00:00
DetermineRuntimeLevel ( ) ;
2020-11-10 08:50:47 +00:00
if ( State . Level < = RuntimeLevel . BootFailed )
2020-12-15 15:20:36 +00:00
{
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-12-15 15:20:36 +00:00
}
2020-05-08 17:30:30 +10:00
2020-12-15 15:20:36 +00:00
IApplicationShutdownRegistry hostingEnvironmentLifetime = _applicationShutdownRegistry ;
2020-03-25 15:06:22 +11:00
if ( hostingEnvironmentLifetime = = null )
2020-12-15 15:20:36 +00: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(StartAsync)}" ) ;
}
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-24 09:22:38 +00:00
AcquireMainDom ( ) ;
2020-03-25 15:06:22 +11:00
2020-12-15 15:20:36 +00:00
await _eventAggregator . PublishAsync ( new UmbracoApplicationStarting ( State . Level ) , cancellationToken ) ;
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
2021-01-18 15:40:22 +01:00
private void DoUnattendedInstall ( )
{
State . DoUnattendedInstall ( ) ;
}
2020-12-15 15:20:36 +00:00
public async Task StopAsync ( CancellationToken cancellationToken )
2016-09-11 19:57:33 +02:00
{
2020-11-24 09:22:38 +00:00
_components . Terminate ( ) ;
2020-12-15 15:20:36 +00:00
await _eventAggregator . PublishAsync ( new UmbracoApplicationStopping ( ) , cancellationToken ) ;
StaticApplicationLogging . Initialize ( null ) ;
2016-09-11 19:57:33 +02:00
}
2016-09-01 19:06:08 +02:00
2020-11-24 09:22:38 +00:00
private void AcquireMainDom ( )
2016-09-11 19:57:33 +02:00
{
2020-12-15 15:20:36 +00:00
using ( DisposableTimer timer = _profilingLogger . DebugDuration < CoreRuntime > ( "Acquiring MainDom." , "Acquired." ) )
2016-09-11 19:57:33 +02:00
{
try
{
2020-11-24 09:22:38 +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 ( )
{
2020-12-15 15:20:36 +00:00
using DisposableTimer timer = _profilingLogger . DebugDuration < CoreRuntime > ( "Determining runtime level." , "Determined." ) ;
2020-11-19 20:05:28 +00:00
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
{
2020-11-24 09:22:38 +00:00
State . Configure ( RuntimeLevel . BootFailed , RuntimeLevelReason . BootFailedOnException ) ;
2020-11-19 20:05:28 +00:00
timer ? . Fail ( ) ;
throw ;
}
}
2016-08-25 15:09:51 +02:00
}
}