mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-01-23 21:32:14 +08:00
Merge pull request #5770 from OrchardCMS/feature/tenantstateinitializing
Changed the handling of the Initializing shell status.
This commit is contained in:
@@ -44,12 +44,9 @@ namespace Orchard.Setup.Controllers {
|
||||
|
||||
public ActionResult Index() {
|
||||
var initialSettings = _setupService.Prime();
|
||||
|
||||
if(initialSettings.State == TenantState.Initializing)
|
||||
return View("Initializing");
|
||||
|
||||
var recipes = _setupService.Recipes().ToList();
|
||||
string recipeDescription = null;
|
||||
|
||||
if (recipes.Count > 0) {
|
||||
recipeDescription = recipes[0].Description;
|
||||
}
|
||||
|
||||
@@ -137,9 +137,6 @@
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Document.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Setup\Initializing.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
||||
@@ -69,6 +69,17 @@ namespace Orchard.Setup.Services {
|
||||
}
|
||||
|
||||
public string Setup(SetupContext context) {
|
||||
var initialState = _shellSettings.State;
|
||||
try {
|
||||
return SetupInternal(context);
|
||||
}
|
||||
catch {
|
||||
_shellSettings.State = initialState;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private string SetupInternal(SetupContext context) {
|
||||
string executionId;
|
||||
|
||||
Logger.Information("Running setup for tenant '{0}'.", _shellSettings.Name);
|
||||
@@ -86,6 +97,9 @@ namespace Orchard.Setup.Services {
|
||||
|
||||
context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty<string>()).Distinct().ToList();
|
||||
|
||||
// Set shell state to "Initializing" so that subsequent HTTP requests are responded to with "Service Unavailable" while Orchard is setting up.
|
||||
_shellSettings.State = TenantState.Initializing;
|
||||
|
||||
var shellSettings = new ShellSettings(_shellSettings);
|
||||
|
||||
if (String.IsNullOrEmpty(shellSettings.DataProvider)) {
|
||||
@@ -93,7 +107,7 @@ namespace Orchard.Setup.Services {
|
||||
shellSettings.DataConnectionString = context.DatabaseConnectionString;
|
||||
shellSettings.DataTablePrefix = context.DatabaseTablePrefix;
|
||||
}
|
||||
|
||||
|
||||
shellSettings.EncryptionAlgorithm = "AES";
|
||||
|
||||
// Randomly generated key.
|
||||
@@ -161,10 +175,7 @@ namespace Orchard.Setup.Services {
|
||||
// Creating a standalone environment.
|
||||
// in theory this environment can be used to resolve any normal components by interface, and those
|
||||
// components will exist entirely in isolation - no crossover between the safemode container currently in effect.
|
||||
|
||||
// Set shell state to "Running" so that the proper shell context is created.
|
||||
shellSettings.State = TenantState.Running;
|
||||
using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
|
||||
using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings, StandaloneEnvironmentOptions.RunningEnvironment)) {
|
||||
try {
|
||||
executionId = CreateTenantData(context, environment);
|
||||
}
|
||||
@@ -174,10 +185,7 @@ namespace Orchard.Setup.Services {
|
||||
}
|
||||
}
|
||||
|
||||
// Set shell state to "Initializing" so that subsequent HTTP requests are responded to with "Service Unavailable" while Orchard is setting up.
|
||||
shellSettings.State = _shellSettings.State = TenantState.Initializing;
|
||||
_shellSettingsManager.SaveSettings(shellSettings);
|
||||
|
||||
return executionId;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
@T("Orchard is initializing. Please check back in a few minutes.")
|
||||
@@ -193,13 +193,12 @@ namespace Orchard.Commands {
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
|
||||
private IContainer CreateHostContainer() {
|
||||
var hostContainer = OrchardStarter.CreateHostContainer(ContainerRegistrations);
|
||||
|
||||
var host = hostContainer.Resolve<IOrchardHost>();
|
||||
|
||||
host.Initialize();
|
||||
return hostContainer;
|
||||
}
|
||||
|
||||
|
||||
private IWorkContextScope CreateStandaloneEnvironment(string tenant) {
|
||||
var host = _hostContainer.Resolve<IOrchardHost>();
|
||||
var tenantManager = _hostContainer.Resolve<IShellSettingsManager>();
|
||||
@@ -216,13 +215,12 @@ namespace Orchard.Commands {
|
||||
return env;
|
||||
}
|
||||
else {
|
||||
// In case of an unitiliazed site (no default settings yet), we create a default settings instance.
|
||||
// In case of an uninitialized site (no default settings yet), we create a default settings instance.
|
||||
var settings = new ShellSettings { Name = ShellSettings.DefaultName, State = TenantState.Uninitialized };
|
||||
return host.CreateStandaloneEnvironment(settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void ContainerRegistrations(ContainerBuilder builder) {
|
||||
MvcSingletons(builder);
|
||||
|
||||
@@ -234,14 +232,14 @@ namespace Orchard.Commands {
|
||||
private CommandHostShellContainerRegistrations CreateShellRegistrations() {
|
||||
return new CommandHostShellContainerRegistrations {
|
||||
Registrations = shellBuilder => {
|
||||
shellBuilder.RegisterType<CommandHostVirtualPathMonitor>()
|
||||
.As<IVirtualPathMonitor>()
|
||||
.As<IVolatileProvider>()
|
||||
.InstancePerMatchingLifetimeScope("shell");
|
||||
shellBuilder.RegisterType<CommandBackgroundService>()
|
||||
.As<IBackgroundService>()
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
shellBuilder.RegisterType<CommandHostVirtualPathMonitor>()
|
||||
.As<IVirtualPathMonitor>()
|
||||
.As<IVolatileProvider>()
|
||||
.InstancePerMatchingLifetimeScope("shell");
|
||||
shellBuilder.RegisterType<CommandBackgroundService>()
|
||||
.As<IBackgroundService>()
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -382,7 +382,7 @@ namespace Orchard.Data.Migration.Interpreters {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
_sqlStatements.Clear();
|
||||
_sqlStatements.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment.Configuration;
|
||||
@@ -12,6 +11,8 @@ using Orchard.Environment.Descriptor;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Mvc.Extensions;
|
||||
using Orchard.Utility.Extensions;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
@@ -26,12 +27,13 @@ namespace Orchard.Environment {
|
||||
private readonly IExtensionLoaderCoordinator _extensionLoaderCoordinator;
|
||||
private readonly IExtensionMonitoringCoordinator _extensionMonitoringCoordinator;
|
||||
private readonly ICacheManager _cacheManager;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly static object _syncLock = new object();
|
||||
private readonly static object _shellContextsWriteLock = new object();
|
||||
|
||||
private IEnumerable<ShellContext> _shellContexts;
|
||||
|
||||
private readonly ContextState<IList<ShellSettings>> _tenantsToRestart;
|
||||
|
||||
public DefaultOrchardHost(
|
||||
IShellSettingsManager shellSettingsManager,
|
||||
IShellContextFactory shellContextFactory,
|
||||
@@ -40,7 +42,9 @@ namespace Orchard.Environment {
|
||||
IExtensionLoaderCoordinator extensionLoaderCoordinator,
|
||||
IExtensionMonitoringCoordinator extensionMonitoringCoordinator,
|
||||
ICacheManager cacheManager,
|
||||
IHostLocalRestart hostLocalRestart) {
|
||||
IHostLocalRestart hostLocalRestart,
|
||||
IHttpContextAccessor httpContextAccessor) {
|
||||
|
||||
_shellSettingsManager = shellSettingsManager;
|
||||
_shellContextFactory = shellContextFactory;
|
||||
_runningShellTable = runningShellTable;
|
||||
@@ -49,6 +53,7 @@ namespace Orchard.Environment {
|
||||
_extensionMonitoringCoordinator = extensionMonitoringCoordinator;
|
||||
_cacheManager = cacheManager;
|
||||
_hostLocalRestart = hostLocalRestart;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
|
||||
_tenantsToRestart = new ContextState<IList<ShellSettings>>("DefaultOrchardHost.TenantsToRestart", () => new List<ShellSettings>());
|
||||
|
||||
@@ -87,13 +92,13 @@ namespace Orchard.Environment {
|
||||
EndRequest();
|
||||
}
|
||||
|
||||
IWorkContextScope IOrchardHost.CreateStandaloneEnvironment(ShellSettings shellSettings) {
|
||||
IWorkContextScope IOrchardHost.CreateStandaloneEnvironment(ShellSettings shellSettings, StandaloneEnvironmentOptions options) {
|
||||
Logger.Debug("Creating standalone environment for tenant {0}", shellSettings.Name);
|
||||
|
||||
MonitorExtensions();
|
||||
BuildCurrent();
|
||||
|
||||
var shellContext = CreateShellContext(shellSettings);
|
||||
var shellContext = CreateShellContext(shellSettings, options);
|
||||
var workContext = shellContext.LifetimeScope.CreateWorkContextScope();
|
||||
return new StandaloneEnvironmentWorkContextScopeWrapper(workContext, shellContext);
|
||||
}
|
||||
@@ -138,7 +143,7 @@ namespace Orchard.Environment {
|
||||
if (allSettings.Any()) {
|
||||
Parallel.ForEach(allSettings, settings => {
|
||||
try {
|
||||
var context = CreateShellContext(settings);
|
||||
var context = CreateShellContext(settings, StandaloneEnvironmentOptions.None);
|
||||
ActivateShell(context);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
@@ -190,16 +195,14 @@ namespace Orchard.Environment {
|
||||
/// <summary>
|
||||
/// Creates a shell context based on shell settings.
|
||||
/// </summary>
|
||||
private ShellContext CreateShellContext(ShellSettings settings) {
|
||||
switch (settings.State) {
|
||||
case TenantState.Uninitialized:
|
||||
case TenantState.Initializing:
|
||||
Logger.Debug("Creating shell context for tenant {0} setup.", settings.Name);
|
||||
return _shellContextFactory.CreateSetupContext(settings);
|
||||
default:
|
||||
Logger.Debug("Creating shell context for tenant {0}.", settings.Name);
|
||||
return _shellContextFactory.CreateShellContext(settings);
|
||||
private ShellContext CreateShellContext(ShellSettings settings, StandaloneEnvironmentOptions options) {
|
||||
if (settings.State != TenantState.Uninitialized || options.Running) {
|
||||
Logger.Debug("Creating shell context for tenant {0}.", settings.Name);
|
||||
return _shellContextFactory.CreateShellContext(settings);
|
||||
}
|
||||
|
||||
Logger.Debug("Creating shell context for tenant {0} setup.", settings.Name);
|
||||
return _shellContextFactory.CreateSetupContext(settings);
|
||||
}
|
||||
|
||||
private void SetupExtensions() {
|
||||
@@ -240,6 +243,8 @@ namespace Orchard.Environment {
|
||||
}
|
||||
|
||||
protected virtual void BeginRequest() {
|
||||
BlockRequestsDuringSetup();
|
||||
|
||||
// Ensure all shell contexts are loaded, or need to be reloaded if
|
||||
// extensions have changed
|
||||
MonitorExtensions();
|
||||
@@ -284,7 +289,7 @@ namespace Orchard.Environment {
|
||||
// is this is a new tenant ? or is it a tenant waiting for setup ?
|
||||
if (shellContext == null || settings.State == TenantState.Uninitialized) {
|
||||
// create the Shell
|
||||
var context = CreateShellContext(settings);
|
||||
var context = CreateShellContext(settings, StandaloneEnvironmentOptions.None);
|
||||
|
||||
// activate the Shell
|
||||
ActivateShell(context);
|
||||
@@ -347,6 +352,25 @@ namespace Orchard.Environment {
|
||||
_tenantsToRestart.GetState().Add(context.Settings);
|
||||
}
|
||||
|
||||
private void BlockRequestsDuringSetup() {
|
||||
var httpContext = _httpContextAccessor.Current();
|
||||
if (httpContext.IsBackgroundContext())
|
||||
return;
|
||||
|
||||
// Get the requested shell.
|
||||
var runningShell = _runningShellTable.Match(httpContext);
|
||||
if (runningShell == null)
|
||||
return;
|
||||
|
||||
// If the requested shell is currently initializing, return a Service Unavailable HTTP status code.
|
||||
if (runningShell.State == TenantState.Initializing) {
|
||||
var response = httpContext.Response;
|
||||
response.StatusCode = 503;
|
||||
response.StatusDescription = "This tenant is currently initializing. Please try again later.";
|
||||
response.Write("This tenant is currently initializing. Please try again later.");
|
||||
}
|
||||
}
|
||||
|
||||
// To be used from CreateStandaloneEnvironment(), also disposes the ShellContext LifetimeScope.
|
||||
private class StandaloneEnvironmentWorkContextScopeWrapper : IWorkContextScope {
|
||||
private readonly ShellContext _shellContext;
|
||||
|
||||
@@ -95,7 +95,6 @@ namespace Orchard.Environment {
|
||||
SafelyTerminate(() => _sweepGenerator.Terminate());
|
||||
}
|
||||
|
||||
|
||||
private void SafelyTerminate(Action action) {
|
||||
try {
|
||||
action();
|
||||
|
||||
@@ -31,6 +31,6 @@ namespace Orchard.Environment {
|
||||
/// Can be used to build an temporary self-contained instance of a shell's configured code.
|
||||
/// Services may be resolved from within this instance to configure and initialize its storage.
|
||||
/// </summary>
|
||||
IWorkContextScope CreateStandaloneEnvironment(ShellSettings shellSettings);
|
||||
IWorkContextScope CreateStandaloneEnvironment(ShellSettings shellSettings, StandaloneEnvironmentOptions options = null);
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Orchard/Environment/StandaloneEnvironmentOptions.cs
Normal file
7
src/Orchard/Environment/StandaloneEnvironmentOptions.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Orchard.Environment {
|
||||
public class StandaloneEnvironmentOptions {
|
||||
public static readonly StandaloneEnvironmentOptions None = new StandaloneEnvironmentOptions();
|
||||
public static readonly StandaloneEnvironmentOptions RunningEnvironment = new StandaloneEnvironmentOptions {Running = true};
|
||||
public bool Running { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -155,6 +155,7 @@
|
||||
<Compile Include="Data\Migration\Schema\DropUniqueConstraintCommand.cs" />
|
||||
<Compile Include="Environment\Extensions\Models\LifecycleStatus.cs" />
|
||||
<Compile Include="Environment\ShellBuilders\ICompositionStrategy.cs" />
|
||||
<Compile Include="Environment\StandaloneEnvironmentOptions.cs" />
|
||||
<Compile Include="IBackgroundHttpContextFactory.cs" />
|
||||
<Compile Include="Mvc\Updater.cs" />
|
||||
<Compile Include="Recipes\Models\ConfigurationContext.cs" />
|
||||
|
||||
Reference in New Issue
Block a user