Fixing shell context activation as per module enabling/disabling

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2011-09-24 20:47:53 -07:00
parent 636bc7b490
commit f4dc89de16
8 changed files with 109 additions and 52 deletions

View File

@@ -139,7 +139,7 @@ namespace Orchard.Tests.Environment {
public void NormalDependenciesShouldBeUniquePerRequestContainer() {
var host = _lifetime.Resolve<IOrchardHost>();
var container1 = host.CreateShellContainer_Obsolete();
((IShellDescriptorManagerEventHandler)host).Changed(null);
((IShellDescriptorManagerEventHandler)host).Changed(null, String.Empty);
var container2 = host.CreateShellContainer_Obsolete();
var requestContainer1a = container1.BeginLifetimeScope();
var requestContainer1b = container1.BeginLifetimeScope();

View File

@@ -2,20 +2,25 @@
using System.Collections.Generic;
using Orchard.Core.Settings.Descriptor.Records;
using Orchard.Data;
using Orchard.Environment.Configuration;
using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.Extensions.Models;
using Orchard.Localization;
namespace Orchard.Core.Settings.Descriptor {
public class ShellDescriptorManager : IShellDescriptorManager {
private readonly IRepository<ShellDescriptorRecord> _shellDescriptorRepository;
private readonly IShellDescriptorManagerEventHandler _events;
private readonly ShellSettings _shellSettings;
public ShellDescriptorManager(
IRepository<ShellDescriptorRecord> shellDescriptorRepository,
IShellDescriptorManagerEventHandler events) {
IShellDescriptorManagerEventHandler events,
ShellSettings shellSettings) {
_shellDescriptorRepository = shellDescriptorRepository;
_events = events;
_shellSettings = shellSettings;
T = NullLocalizer.Instance;
}
@@ -82,9 +87,7 @@ namespace Orchard.Core.Settings.Descriptor {
});
}
_events.Changed(GetShellDescriptorFromRecord(shellDescriptorRecord));
_events.Changed(GetShellDescriptorFromRecord(shellDescriptorRecord), _shellSettings.Name);
}
}
}

View File

@@ -150,6 +150,9 @@ namespace Orchard.Setup.Services {
}
}
_shellSettingsManager.SaveSettings(shellSettings);
// in effect "pump messages" see PostMessage circa 1980
while ( _processingEngine.AreTasksPending() )
_processingEngine.ExecuteNextTask();
@@ -170,11 +173,11 @@ namespace Orchard.Setup.Services {
}
}
while (_processingEngine.AreTasksPending())
_processingEngine.ExecuteNextTask();
_shellSettingsManager.SaveSettings(shellSettings);
//// execute pending recipe steps
//while (_processingEngine.AreTasksPending())
// _processingEngine.ExecuteNextTask();
return executionId;
}

View File

@@ -1,5 +1,6 @@
using System.Linq;
using System.Collections.Generic;
using System.Transactions;
using Orchard.Caching;
using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions;
@@ -23,7 +24,8 @@ namespace Orchard.Environment {
private readonly ICacheManager _cacheManager;
private readonly object _syncLock = new object();
private IEnumerable<ShellContext> _current;
private IEnumerable<ShellContext> _shellContexts;
private IEnumerable<ShellSettings> _tenantsToRestart;
public DefaultOrchardHost(
IShellSettingsManager shellSettingsManager,
@@ -42,6 +44,7 @@ namespace Orchard.Environment {
_extensionMonitoringCoordinator = extensionMonitoringCoordinator;
_cacheManager = cacheManager;
_hostLocalRestart = hostLocalRestart;
_tenantsToRestart = Enumerable.Empty<ShellSettings>();
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
@@ -88,44 +91,65 @@ namespace Orchard.Environment {
return shellContext.LifetimeScope.CreateWorkContextScope();
}
/// <summary>
/// Ensures shells are activated, or re-activated if extensions have changed
/// </summary>
IEnumerable<ShellContext> BuildCurrent() {
if (_current == null) {
if (_shellContexts == null) {
lock (_syncLock) {
if (_current == null) {
if (_shellContexts == null) {
SetupExtensions();
MonitorExtensions();
_current = CreateAndActivate().ToArray();
CreateAndActivateShells();
}
}
}
return _current;
return _shellContexts;
}
IEnumerable<ShellContext> CreateAndActivate() {
void StartUpdatedShells() {
lock (_syncLock) {
if (_tenantsToRestart.Any()) {
foreach (var settings in _tenantsToRestart.Distinct().ToList()) {
ActivateShell(settings);
}
_tenantsToRestart = Enumerable.Empty<ShellSettings>();
}
}
}
void CreateAndActivateShells() {
Logger.Information("Start creation of shells");
IEnumerable<ShellContext> result;
// is there any tenant right now ?
var allSettings = _shellSettingsManager.LoadSettings();
// load all tenants, and activate their shell
if (allSettings.Any()) {
result = allSettings.Select(
settings => {
var context = CreateShellContext(settings);
ActivateShell(context);
return context;
});
foreach (var settings in allSettings) {
var context = CreateShellContext(settings);
ActivateShell(context);
}
}
// no settings, run the Setup
else {
var setupContext = CreateSetupContext();
ActivateShell(setupContext);
result = new[] {setupContext};
}
Logger.Information("Done creating shells");
return result;
}
/// <summary>
/// Start a Shell and register its settings in RunningShellTable
/// </summary>
private void ActivateShell(ShellContext context) {
Logger.Debug("Activating context for tenant {0}", context.Settings.Name);
context.Shell.Activate();
_shellContexts = (_shellContexts ?? Enumerable.Empty<ShellContext>()).Union(new [] {context});
_runningShellTable.Add(context.Settings);
}
@@ -161,27 +185,34 @@ namespace Orchard.Environment {
});
}
/// <summary>
/// Terminates all active shell contexts, and dispose their scope, forcing
/// them to be reloaded if necessary.
/// </summary>
private void DisposeShellContext() {
Logger.Information("Disposing active shell contexts");
if (_current != null) {
foreach (var shellContext in _current) {
if (_shellContexts != null) {
foreach (var shellContext in _shellContexts) {
shellContext.Shell.Terminate();
shellContext.LifetimeScope.Dispose();
}
_current = null;
_shellContexts = null;
}
}
protected virtual void BeginRequest() {
// Ensure all shell contexts are loaded, or need to be reloaded if
// extensions have changed
MonitorExtensions();
BuildCurrent();
StartUpdatedShells();
}
protected virtual void EndRequest() {
// Synchronously process all pending tasks. It's safe to do this at this point
// of the pipeline, as the request transaction has been closed, so creating a new
// environment and transaction for these tasks will behave as expected.
// environment and transaction for these tasks will behave as expected.)
while (_processingEngine.AreTasksPending()) {
_processingEngine.ExecuteNextTask();
}
@@ -190,33 +221,37 @@ namespace Orchard.Environment {
/// <summary>
/// Register and activate a new Shell when a tenant is created
/// </summary>
void IShellSettingsManagerEventHandler.Saved(ShellSettings settings)
{
// is it a new tenant ?
var shellContext = _current.FirstOrDefault(c => c.Settings.Name == settings.Name);
ShellContext context;
// if null, this is a new tenant, register and activate a new context
if(shellContext == null)
{
context = CreateShellContext(settings);
ActivateShell(context);
_current = _current.Union(new[] { context });
_runningShellTable.Add(settings);
void IShellSettingsManagerEventHandler.Saved(ShellSettings settings) {
lock (_syncLock) {
_tenantsToRestart = _tenantsToRestart.Where(x => x.Name != settings.Name).Union(new[] { settings });
}
else
{
context = _shellContextFactory.CreateShellContext(settings);
}
void ActivateShell(ShellSettings settings) {
// look for the associated shell context
var shellContext = _shellContexts.FirstOrDefault(c => c.Settings.Name == settings.Name);
// is this is a new tenant ?
if (shellContext == null) {
// create the Shell
var context = CreateShellContext(settings);
// activate the Shell
ActivateShell(context);
}
// reload the shell as its settings have changed
else {
// dispose previous context
shellContext.Shell.Terminate();
shellContext.LifetimeScope.Dispose();
var context = _shellContextFactory.CreateShellContext(settings);
// activate and register modified context
_current = _current.Where(shell => shell.Settings.Name != settings.Name).Union(new[] { shellContext });
_shellContexts = _shellContexts.Where(shell => shell.Settings.Name != settings.Name).Union(new[] { context });
context.Shell.Activate();
_runningShellTable.Update(settings);
}
}
@@ -224,7 +259,23 @@ namespace Orchard.Environment {
/// <summary>
/// A feature is enabled/disabled
/// </summary>
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor) {
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor, string tenant) {
lock (_syncLock) {
var context = _shellContexts.Where(x => x.Settings.Name == tenant).FirstOrDefault();
// some shells might need to be started, e.g. created by command line
if(context == null) {
StartUpdatedShells();
context = _shellContexts.Where(x => x.Settings.Name == tenant).First();
}
// don't update the settings themselves here
if(_tenantsToRestart.Any(x => x.Name == tenant)) {
return;
}
_tenantsToRestart = _tenantsToRestart.Union(new[] { context.Settings });
}
}
}
}

View File

@@ -28,6 +28,6 @@ namespace Orchard.Environment.Descriptor {
}
public interface IShellDescriptorManagerEventHandler : IEventHandler {
void Changed(ShellDescriptor descriptor);
void Changed(ShellDescriptor descriptor, string tenant);
}
}

View File

@@ -36,7 +36,7 @@ namespace Orchard.Environment {
TouchFile();
}
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor) {
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor, string tenant) {
TouchFile();
}

View File

@@ -89,7 +89,7 @@ namespace Orchard.Environment {
.Where(group => host.EndsWith(group.Key, StringComparison.OrdinalIgnoreCase))
.SelectMany(group => group
.OrderByDescending(settings => (settings.RequestUrlPrefix ?? "").Length))
.Where(settings => settings.State.CurrentState == TenantState.State.Running && appRelativePath.StartsWith(settings.RequestUrlPrefix ?? "", StringComparison.OrdinalIgnoreCase))
.Where(settings => settings.State.CurrentState != TenantState.State.Disabled && appRelativePath.StartsWith(settings.RequestUrlPrefix ?? "", StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
return mostQualifiedMatch ?? _fallback;

View File

@@ -33,7 +33,7 @@ namespace Orchard.Environment.State {
public ILogger Logger { get; set; }
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor) {
void IShellDescriptorManagerEventHandler.Changed(ShellDescriptor descriptor, string tenant) {
// deduce and apply state changes involved
var shellState = _stateManager.GetShellState();
foreach (var feature in descriptor.Features) {