mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Refactoring ITransactionManager to remove usage of TransationScope
Adds a new RequireNew() method to start a new transactions. --HG-- branch : 1.x
This commit is contained in:
parent
da6fd5fac6
commit
c5aa1382e7
@ -27,6 +27,7 @@ using Orchard.Messaging.Services;
|
||||
using Orchard.Security;
|
||||
using Orchard.Security.Permissions;
|
||||
using Orchard.Security.Providers;
|
||||
using Orchard.Tests.ContentManagement;
|
||||
using Orchard.Tests.Stubs;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Users.Controllers;
|
||||
@ -65,7 +66,8 @@ namespace Orchard.Tests.Modules.Users.Controllers {
|
||||
builder.RegisterType<UserService>().As<IUserService>();
|
||||
builder.RegisterType<UserPartHandler>().As<IContentHandler>();
|
||||
builder.RegisterType<OrchardServices>().As<IOrchardServices>();
|
||||
builder.RegisterType<TransactionManager>().As<ITransactionManager>();
|
||||
|
||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ITransactionManager>();
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
|
||||
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
||||
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
|
||||
|
@ -84,7 +84,7 @@ namespace Orchard.Tests.ContentManagement {
|
||||
_manager = _container.Resolve<IContentManager>();
|
||||
}
|
||||
|
||||
public class TestSessionLocator : ISessionLocator {
|
||||
public class TestSessionLocator : ISessionLocator, ITransactionManager {
|
||||
private readonly ISession _session;
|
||||
|
||||
public TestSessionLocator(ISession session) {
|
||||
@ -94,6 +94,15 @@ namespace Orchard.Tests.ContentManagement {
|
||||
public ISession For(Type entityType) {
|
||||
return _session;
|
||||
}
|
||||
|
||||
public void Demand() {
|
||||
}
|
||||
|
||||
public void RequireNew() {
|
||||
}
|
||||
|
||||
public void Cancel() {
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -1,21 +1,20 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using NHibernate;
|
||||
using NHibernate.SqlCommand;
|
||||
using NHibernate.Type;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public class SessionLocator : ISessionLocator {
|
||||
public class SessionLocator : ISessionLocator, ITransactionManager, IDisposable {
|
||||
private readonly ISessionFactoryHolder _sessionFactoryHolder;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
private ISession _session;
|
||||
private ITransaction _transaction;
|
||||
private bool _cancelled;
|
||||
|
||||
public SessionLocator(
|
||||
ISessionFactoryHolder sessionFactoryHolder,
|
||||
ITransactionManager transactionManager) {
|
||||
public SessionLocator(ISessionFactoryHolder sessionFactoryHolder) {
|
||||
_sessionFactoryHolder = sessionFactoryHolder;
|
||||
_transactionManager = transactionManager;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
@ -24,18 +23,76 @@ namespace Orchard.Data {
|
||||
public ISession For(Type entityType) {
|
||||
Logger.Debug("Acquiring session for {0}", entityType);
|
||||
|
||||
if (_session == null) {
|
||||
((ITransactionManager)this).Demand();
|
||||
|
||||
var sessionFactory = _sessionFactoryHolder.GetSessionFactory();
|
||||
|
||||
_transactionManager.Demand();
|
||||
|
||||
Logger.Information("Openning database session");
|
||||
_session = sessionFactory.OpenSession(new SessionInterceptor());
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
void ITransactionManager.Demand() {
|
||||
EnsureSession();
|
||||
|
||||
if (_transaction == null) {
|
||||
Logger.Debug("Creating transaction on Demand");
|
||||
_transaction = _session.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
}
|
||||
}
|
||||
|
||||
void ITransactionManager.RequireNew() {
|
||||
EnsureSession();
|
||||
|
||||
if (_cancelled) {
|
||||
_transaction.Rollback();
|
||||
_transaction.Dispose();
|
||||
_transaction = null;
|
||||
}
|
||||
else {
|
||||
if (_transaction != null) {
|
||||
_transaction.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Debug("Creating transaction on RequireNew");
|
||||
_transaction = _session.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
}
|
||||
|
||||
void ITransactionManager.Cancel() {
|
||||
Logger.Debug("Transaction cancelled flag set");
|
||||
|
||||
if (_transaction != null && !_transaction.WasRolledBack) {
|
||||
_transaction.Rollback();
|
||||
}
|
||||
|
||||
_cancelled = true;
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
if (_transaction != null) {
|
||||
if (!_cancelled) {
|
||||
Logger.Debug("Marking transaction as complete");
|
||||
_transaction.Commit();
|
||||
}
|
||||
else {
|
||||
Logger.Debug("Reverting operations from transaction");
|
||||
_transaction.Rollback();
|
||||
}
|
||||
|
||||
_transaction.Dispose();
|
||||
Logger.Debug("Transaction disposed");
|
||||
|
||||
_cancelled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureSession() {
|
||||
if (_session != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var sessionFactory = _sessionFactoryHolder.GetSessionFactory();
|
||||
Logger.Information("Openning database session");
|
||||
_session = sessionFactory.OpenSession(new SessionInterceptor());
|
||||
}
|
||||
|
||||
class SessionInterceptor : IInterceptor {
|
||||
private ISession _session;
|
||||
|
||||
|
@ -1,72 +1,13 @@
|
||||
using System;
|
||||
using System.Transactions;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Logging;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Mvc.Filters;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public interface ITransactionManager : IDependency {
|
||||
void Demand();
|
||||
void RequireNew();
|
||||
void Cancel();
|
||||
}
|
||||
|
||||
public class TransactionManager : ITransactionManager, IDisposable {
|
||||
private TransactionScope _scope;
|
||||
private bool _cancelled;
|
||||
|
||||
public TransactionManager() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
void ITransactionManager.Demand() {
|
||||
if(_cancelled) {
|
||||
try {
|
||||
_scope.Dispose();
|
||||
}
|
||||
catch {
|
||||
// swallowing the exception
|
||||
}
|
||||
|
||||
_scope = null;
|
||||
}
|
||||
|
||||
if (_scope == null) {
|
||||
Logger.Debug("Creating transaction on Demand");
|
||||
_scope = new TransactionScope(
|
||||
TransactionScopeOption.Required,
|
||||
new TransactionOptions {
|
||||
IsolationLevel = IsolationLevel.ReadCommitted
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ITransactionManager.Cancel() {
|
||||
Logger.Debug("Transaction cancelled flag set");
|
||||
_cancelled = true;
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
if (_scope != null) {
|
||||
if (!_cancelled) {
|
||||
Logger.Debug("Marking transaction as complete");
|
||||
_scope.Complete();
|
||||
}
|
||||
|
||||
Logger.Debug("Final work for transaction being performed");
|
||||
try {
|
||||
_scope.Dispose();
|
||||
}
|
||||
catch {
|
||||
// swallowing the exception
|
||||
}
|
||||
Logger.Debug("Transaction disposed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TransactionFilter : FilterProvider, IExceptionFilter {
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Transactions;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Data;
|
||||
using Orchard.Events;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Tasks {
|
||||
@ -15,26 +12,28 @@ namespace Orchard.Tasks {
|
||||
|
||||
[UsedImplicitly]
|
||||
public class BackgroundService : IBackgroundService {
|
||||
private readonly IEnumerable<IEventHandler> _tasks;
|
||||
private readonly IEnumerable<IBackgroundTask> _tasks;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
|
||||
public BackgroundService(IEnumerable<IEventHandler> tasks) {
|
||||
public BackgroundService(IEnumerable<IBackgroundTask> tasks, ITransactionManager transactionManager) {
|
||||
_tasks = tasks;
|
||||
_transactionManager = transactionManager;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void Sweep() {
|
||||
foreach(var task in _tasks.OfType<IBackgroundTask>()) {
|
||||
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew)) {
|
||||
try {
|
||||
task.Sweep();
|
||||
scope.Complete();
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Error while processing background task");
|
||||
}
|
||||
foreach(var task in _tasks) {
|
||||
try {
|
||||
_transactionManager.RequireNew();
|
||||
task.Sweep();
|
||||
}
|
||||
catch (Exception e) {
|
||||
_transactionManager.Cancel();
|
||||
Logger.Error(e, "Error while processing background task");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Timers;
|
||||
using Orchard.Data;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Tasks {
|
||||
@ -61,9 +60,6 @@ namespace Orchard.Tasks {
|
||||
|
||||
public void DoWork() {
|
||||
using (var scope = _workContextAccessor.CreateWorkContextScope()) {
|
||||
var transactionManager = scope.Resolve<ITransactionManager>();
|
||||
transactionManager.Demand();
|
||||
|
||||
// resolve the manager and invoke it
|
||||
var manager = scope.Resolve<IBackgroundService>();
|
||||
manager.Sweep();
|
||||
|
Loading…
Reference in New Issue
Block a user