Process all pending tasks at the end of the request

Instead of processing tasks asynchronously at the end of a request,
we process them synchronously, so that the behavior is more
deterministic.

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-12-04 14:11:18 -08:00
parent 3a4a4b7837
commit 5ab00ebabe
2 changed files with 26 additions and 22 deletions

View File

@@ -147,6 +147,8 @@ namespace Orchard.Environment {
} }
private void DisposeShellContext() { private void DisposeShellContext() {
Logger.Information("Disposing active shell contexts");
if (_current != null) { if (_current != null) {
foreach (var shellContext in _current) { foreach (var shellContext in _current) {
shellContext.Shell.Terminate(); shellContext.Shell.Terminate();
@@ -160,24 +162,13 @@ namespace Orchard.Environment {
BuildCurrent(); BuildCurrent();
} }
// the exit gate is temporary, until better control strategy is in place
private readonly ManualResetEvent _exitGate = new ManualResetEvent(true);
protected virtual void EndRequest() { protected virtual void EndRequest() {
if (_processingEngine.AreTasksPending()) { // Synchronously process all pending tasks. It's safe to do this at this point
_exitGate.Reset(); // of the pipeline, as the request transaction has been closed, so creating a new
ThreadPool.QueueUserWorkItem(state => { // environment and transaction for these tasks will behave as expected.
while (_processingEngine.AreTasksPending()) { while (_processingEngine.AreTasksPending()) {
_processingEngine.ExecuteNextTask(); _processingEngine.ExecuteNextTask();
if (!_processingEngine.AreTasksPending()) {
_exitGate.Set();
}
}
});
} }
_exitGate.WaitOne(250);
} }
void IShellSettingsManagerEventHandler.Saved(ShellSettings settings) { void IShellSettingsManagerEventHandler.Saved(ShellSettings settings) {

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Orchard.Data;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Environment.ShellBuilders; using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Descriptor.Models; using Orchard.Environment.Descriptor.Models;
@@ -69,13 +70,25 @@ namespace Orchard.Environment.State {
var shellContext = _shellContextFactory.CreateDescribedContext(entry.ShellSettings, entry.ShellDescriptor); var shellContext = _shellContextFactory.CreateDescribedContext(entry.ShellSettings, entry.ShellDescriptor);
using (shellContext.LifetimeScope) { using (shellContext.LifetimeScope) {
using (var standaloneEnvironment = shellContext.LifetimeScope.CreateWorkContextScope()) { using (var standaloneEnvironment = shellContext.LifetimeScope.CreateWorkContextScope()) {
var eventBus = standaloneEnvironment.Resolve<IEventBus>();
Logger.Information("Executing event {0} in process {1} for shell {2}", ITransactionManager transactionManager;
entry.MessageName, if (!standaloneEnvironment.TryResolve(out transactionManager))
entry.ProcessId, transactionManager = null;
entry.ShellSettings.Name);
eventBus.NotifyFailFast(entry.MessageName, entry.EventData); try {
var eventBus = standaloneEnvironment.Resolve<IEventBus>();
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;
}
} }
} }
} }