diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index 7d5f0b5d1..59d6204cb 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -147,6 +147,8 @@ namespace Orchard.Environment { } private void DisposeShellContext() { + Logger.Information("Disposing active shell contexts"); + if (_current != null) { foreach (var shellContext in _current) { shellContext.Shell.Terminate(); @@ -160,24 +162,13 @@ namespace Orchard.Environment { BuildCurrent(); } - - // the exit gate is temporary, until better control strategy is in place - private readonly ManualResetEvent _exitGate = new ManualResetEvent(true); - protected virtual void EndRequest() { - if (_processingEngine.AreTasksPending()) { - _exitGate.Reset(); - ThreadPool.QueueUserWorkItem(state => { - while (_processingEngine.AreTasksPending()) { - _processingEngine.ExecuteNextTask(); - if (!_processingEngine.AreTasksPending()) { - _exitGate.Set(); - } - } - }); + // 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. + while (_processingEngine.AreTasksPending()) { + _processingEngine.ExecuteNextTask(); } - - _exitGate.WaitOne(250); } void IShellSettingsManagerEventHandler.Saved(ShellSettings settings) { diff --git a/src/Orchard/Environment/State/DefaultProcessingEngine.cs b/src/Orchard/Environment/State/DefaultProcessingEngine.cs index 003718119..b1838316c 100644 --- a/src/Orchard/Environment/State/DefaultProcessingEngine.cs +++ b/src/Orchard/Environment/State/DefaultProcessingEngine.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Orchard.Data; using Orchard.Environment.Configuration; using Orchard.Environment.ShellBuilders; using Orchard.Environment.Descriptor.Models; @@ -69,13 +70,25 @@ namespace Orchard.Environment.State { var shellContext = _shellContextFactory.CreateDescribedContext(entry.ShellSettings, entry.ShellDescriptor); using (shellContext.LifetimeScope) { using (var standaloneEnvironment = shellContext.LifetimeScope.CreateWorkContextScope()) { - var eventBus = standaloneEnvironment.Resolve(); - Logger.Information("Executing event {0} in process {1} for shell {2}", - entry.MessageName, - entry.ProcessId, - entry.ShellSettings.Name); - eventBus.NotifyFailFast(entry.MessageName, entry.EventData); + ITransactionManager transactionManager; + if (!standaloneEnvironment.TryResolve(out transactionManager)) + transactionManager = null; + + try { + var eventBus = standaloneEnvironment.Resolve(); + Logger.Information("Executing event {0} in process {1} for shell {2}", + entry.MessageName, + entry.ProcessId, + entry.ShellSettings.Name); + eventBus.Notify(entry.MessageName, entry.EventData); + } + catch { + // any database changes in this using(env) scope are invalidated + if (transactionManager != null) + transactionManager.Cancel(); + throw; + } } } }