Skip to content

Commit 364b8f1

Browse files
Add UmbracoApplicationStartedNotification and UmbracoApplicationStoppedNotification (#11857)
* Add UmbracoApplicationStartedNotification and UmbracoApplicationStoppedNotification * Include cancellation token when publishing unattended install/upgrade notifications
1 parent bf16622 commit 364b8f1

File tree

5 files changed

+99
-30
lines changed

5 files changed

+99
-30
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Umbraco.Cms.Core.Notifications
2+
{
3+
/// <summary>
4+
/// Notification that occurs when Umbraco has completely booted up and the request processing pipeline is configured.
5+
/// </summary>
6+
/// <seealso cref="Umbraco.Cms.Core.Notifications.INotification" />
7+
public class UmbracoApplicationStartedNotification : INotification
8+
{ }
9+
}
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
// Copyright (c) Umbraco.
2-
// See LICENSE for more details.
3-
41
namespace Umbraco.Cms.Core.Notifications
52
{
63
/// <summary>
7-
/// Notification that occurs at the very end of the Umbraco boot
8-
/// process and after all <see cref="IComponent"/> initialize.
4+
/// Notification that occurs at the very end of the Umbraco boot process (after all <see cref="IComponent" />s are initialized).
95
/// </summary>
6+
/// <seealso cref="Umbraco.Cms.Core.Notifications.INotification" />
107
public class UmbracoApplicationStartingNotification : INotification
118
{
129
/// <summary>
13-
/// Initializes a new instance of the <see cref="UmbracoApplicationStartingNotification"/> class.
10+
/// Initializes a new instance of the <see cref="UmbracoApplicationStartingNotification" /> class.
1411
/// </summary>
1512
/// <param name="runtimeLevel">The runtime level</param>
1613
public UmbracoApplicationStartingNotification(RuntimeLevel runtimeLevel) => RuntimeLevel = runtimeLevel;
1714

1815
/// <summary>
19-
/// Gets the runtime level of execution.
16+
/// Gets the runtime level.
2017
/// </summary>
18+
/// <value>
19+
/// The runtime level.
20+
/// </value>
2121
public RuntimeLevel RuntimeLevel { get; }
2222
}
2323
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Umbraco.Cms.Core.Notifications
2+
{
3+
/// <summary>
4+
/// Notification that occurs when Umbraco has completely shutdown.
5+
/// </summary>
6+
/// <seealso cref="Umbraco.Cms.Core.Notifications.INotification" />
7+
public class UmbracoApplicationStoppedNotification : INotification
8+
{ }
9+
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
namespace Umbraco.Cms.Core.Notifications
22
{
3-
public class UmbracoApplicationStoppingNotification : INotification { }
3+
/// <summary>
4+
/// Notification that occurs when Umbraco is shutting down (after all <see cref="IComponent" />s are terminated).
5+
/// </summary>
6+
/// <seealso cref="Umbraco.Cms.Core.Notifications.INotification" />
7+
public class UmbracoApplicationStoppingNotification : INotification
8+
{ }
49
}

src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using System.ComponentModel;
33
using System.Threading;
44
using System.Threading.Tasks;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.Hosting;
57
using Microsoft.Extensions.Logging;
68
using Umbraco.Cms.Core;
79
using Umbraco.Cms.Core.Configuration;
@@ -16,12 +18,13 @@
1618
using Umbraco.Cms.Web.Common.DependencyInjection;
1719
using Umbraco.Extensions;
1820
using ComponentCollection = Umbraco.Cms.Core.Composing.ComponentCollection;
21+
using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
1922

2023
namespace Umbraco.Cms.Infrastructure.Runtime
2124
{
25+
/// <inheritdoc />
2226
public class CoreRuntime : IRuntime
2327
{
24-
private readonly ILogger<CoreRuntime> _logger;
2528
private readonly ILoggerFactory _loggerFactory;
2629
private readonly ComponentCollection _components;
2730
private readonly IApplicationShutdownRegistry _applicationShutdownRegistry;
@@ -32,14 +35,16 @@ public class CoreRuntime : IRuntime
3235
private readonly IHostingEnvironment _hostingEnvironment;
3336
private readonly IUmbracoVersion _umbracoVersion;
3437
private readonly IServiceProvider _serviceProvider;
38+
private readonly IHostApplicationLifetime _hostApplicationLifetime;
39+
private readonly ILogger<CoreRuntime> _logger;
3540
private CancellationToken _cancellationToken;
3641

3742
/// <summary>
38-
/// Initializes a new instance of the <see cref="CoreRuntime"/> class.
43+
/// Initializes a new instance of the <see cref="CoreRuntime" /> class.
3944
/// </summary>
4045
public CoreRuntime(
41-
ILoggerFactory loggerFactory,
4246
IRuntimeState state,
47+
ILoggerFactory loggerFactory,
4348
ComponentCollection components,
4449
IApplicationShutdownRegistry applicationShutdownRegistry,
4550
IProfilingLogger profilingLogger,
@@ -48,9 +53,11 @@ public CoreRuntime(
4853
IEventAggregator eventAggregator,
4954
IHostingEnvironment hostingEnvironment,
5055
IUmbracoVersion umbracoVersion,
51-
IServiceProvider serviceProvider)
56+
IServiceProvider serviceProvider,
57+
IHostApplicationLifetime hostApplicationLifetime)
5258
{
5359
State = state;
60+
5461
_loggerFactory = loggerFactory;
5562
_components = components;
5663
_applicationShutdownRegistry = applicationShutdownRegistry;
@@ -61,6 +68,7 @@ public CoreRuntime(
6168
_hostingEnvironment = hostingEnvironment;
6269
_umbracoVersion = umbracoVersion;
6370
_serviceProvider = serviceProvider;
71+
_hostApplicationLifetime = hostApplicationLifetime;
6472
_logger = _loggerFactory.CreateLogger<CoreRuntime>();
6573
}
6674

@@ -76,23 +84,49 @@ public CoreRuntime(
7684
IUmbracoDatabaseFactory databaseFactory,
7785
IEventAggregator eventAggregator,
7886
IHostingEnvironment hostingEnvironment,
79-
IUmbracoVersion umbracoVersion
80-
):this(
81-
loggerFactory,
82-
state,
83-
components,
84-
applicationShutdownRegistry,
85-
profilingLogger,
86-
mainDom,
87-
databaseFactory,
88-
eventAggregator,
89-
hostingEnvironment,
90-
umbracoVersion,
91-
null
92-
)
93-
{
87+
IUmbracoVersion umbracoVersion,
88+
IServiceProvider serviceProvider)
89+
: this(
90+
state,
91+
loggerFactory,
92+
components,
93+
applicationShutdownRegistry,
94+
profilingLogger,
95+
mainDom,
96+
databaseFactory,
97+
eventAggregator,
98+
hostingEnvironment,
99+
umbracoVersion,
100+
serviceProvider,
101+
serviceProvider?.GetRequiredService<IHostApplicationLifetime>())
102+
{ }
94103

95-
}
104+
[EditorBrowsable(EditorBrowsableState.Never)]
105+
[Obsolete]
106+
public CoreRuntime(
107+
ILoggerFactory loggerFactory,
108+
IRuntimeState state,
109+
ComponentCollection components,
110+
IApplicationShutdownRegistry applicationShutdownRegistry,
111+
IProfilingLogger profilingLogger,
112+
IMainDom mainDom,
113+
IUmbracoDatabaseFactory databaseFactory,
114+
IEventAggregator eventAggregator,
115+
IHostingEnvironment hostingEnvironment,
116+
IUmbracoVersion umbracoVersion)
117+
: this(
118+
loggerFactory,
119+
state,
120+
components,
121+
applicationShutdownRegistry,
122+
profilingLogger,
123+
mainDom,
124+
databaseFactory,
125+
eventAggregator,
126+
hostingEnvironment,
127+
umbracoVersion,
128+
null)
129+
{ }
96130

97131
/// <summary>
98132
/// Gets the state of the Umbraco runtime.
@@ -103,13 +137,17 @@ IUmbracoVersion umbracoVersion
103137
public async Task RestartAsync()
104138
{
105139
await StopAsync(_cancellationToken);
140+
await _eventAggregator.PublishAsync(new UmbracoApplicationStoppedNotification(), _cancellationToken);
106141
await StartAsync(_cancellationToken);
142+
await _eventAggregator.PublishAsync(new UmbracoApplicationStartedNotification(), _cancellationToken);
107143
}
108144

109145
/// <inheritdoc/>
110146
public async Task StartAsync(CancellationToken cancellationToken)
111147
{
148+
// Store token, so we can re-use this during restart
112149
_cancellationToken = cancellationToken;
150+
113151
StaticApplicationLogging.Initialize(_loggerFactory);
114152
StaticServiceProvider.Instance = _serviceProvider;
115153

@@ -130,14 +168,21 @@ public async Task StartAsync(CancellationToken cancellationToken)
130168
_logger.LogError(exception, msg);
131169
};
132170

171+
// Add application started and stopped notifications (only on initial startup, not restarts)
172+
if (_hostApplicationLifetime.ApplicationStarted.IsCancellationRequested == false)
173+
{
174+
_hostApplicationLifetime.ApplicationStarted.Register(() => _eventAggregator.Publish(new UmbracoApplicationStartedNotification()));
175+
_hostApplicationLifetime.ApplicationStopped.Register(() => _eventAggregator.Publish(new UmbracoApplicationStoppedNotification()));
176+
}
177+
133178
// acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
134179
AcquireMainDom();
135180

136181
// TODO (V10): Remove this obsoleted notification publish.
137182
await _eventAggregator.PublishAsync(new UmbracoApplicationMainDomAcquiredNotification(), cancellationToken);
138183

139184
// notify for unattended install
140-
await _eventAggregator.PublishAsync(new RuntimeUnattendedInstallNotification());
185+
await _eventAggregator.PublishAsync(new RuntimeUnattendedInstallNotification(), cancellationToken);
141186
DetermineRuntimeLevel();
142187

143188
if (!State.UmbracoCanBoot())
@@ -153,14 +198,15 @@ public async Task StartAsync(CancellationToken cancellationToken)
153198

154199
// if level is Run and reason is UpgradeMigrations, that means we need to perform an unattended upgrade
155200
var unattendedUpgradeNotification = new RuntimeUnattendedUpgradeNotification();
156-
await _eventAggregator.PublishAsync(unattendedUpgradeNotification);
201+
await _eventAggregator.PublishAsync(unattendedUpgradeNotification, cancellationToken);
157202
switch (unattendedUpgradeNotification.UnattendedUpgradeResult)
158203
{
159204
case RuntimeUnattendedUpgradeNotification.UpgradeResult.HasErrors:
160205
if (State.BootFailedException == null)
161206
{
162207
throw new InvalidOperationException($"Unattended upgrade result was {RuntimeUnattendedUpgradeNotification.UpgradeResult.HasErrors} but no {nameof(BootFailedException)} was registered");
163208
}
209+
164210
// we cannot continue here, the exception will be rethrown by BootFailedMiddelware
165211
return;
166212
case RuntimeUnattendedUpgradeNotification.UpgradeResult.CoreUpgradeComplete:

0 commit comments

Comments
 (0)