mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Refactored disposal of DatabaseLock.
This ensures the cleanup will be able to resolve a database transaction even when it's Autofac that's disposing the object.
This commit is contained in:
@@ -5,6 +5,7 @@ using Autofac;
|
|||||||
using Orchard.Data;
|
using Orchard.Data;
|
||||||
using Orchard.Environment.Extensions;
|
using Orchard.Environment.Extensions;
|
||||||
using Orchard.Exceptions;
|
using Orchard.Exceptions;
|
||||||
|
using Orchard.Logging;
|
||||||
using Orchard.Services;
|
using Orchard.Services;
|
||||||
using Orchard.TaskLease.Models;
|
using Orchard.TaskLease.Models;
|
||||||
using Orchard.Tasks.Locking;
|
using Orchard.Tasks.Locking;
|
||||||
@@ -23,21 +24,28 @@ namespace Orchard.TaskLease.Services {
|
|||||||
private bool _isAcquired;
|
private bool _isAcquired;
|
||||||
private int _id;
|
private int _id;
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
|
private ILifetimeScope _scope;
|
||||||
|
|
||||||
public DatabaseLock(ILifetimeScope lifetimeScope, IClock clock) {
|
public DatabaseLock(ILifetimeScope lifetimeScope, IClock clock) {
|
||||||
_lifetimeScope = lifetimeScope;
|
_lifetimeScope = lifetimeScope;
|
||||||
_clock = clock;
|
_clock = clock;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
public bool TryAcquire(string name, TimeSpan maxLifetime) {
|
public bool TryAcquire(string name, TimeSpan maxLifetime) {
|
||||||
Argument.ThrowIfNullOrEmpty(name, "name");
|
Argument.ThrowIfNullOrEmpty(name, "name");
|
||||||
|
|
||||||
if (name.Length > 256)
|
if (name.Length > 256)
|
||||||
throw new ArgumentException("The lock's name can't be longer than 256 characters.");
|
throw new ArgumentException("The lock's name can't be longer than 256 characters.");
|
||||||
|
|
||||||
// This way we can create a nested transaction scope instead of having the unwanted effect
|
try {
|
||||||
// of manipulating the transaction of the caller.
|
var scope = EnsureLifetimeScope(name);
|
||||||
using (var scope = BeginLifeTimeScope(name)) {
|
scope.Resolve<ITransactionManager>().RequireNew(IsolationLevel.ReadCommitted);
|
||||||
|
|
||||||
|
// This way we can create a nested transaction scope instead of having the unwanted effect
|
||||||
|
// of manipulating the transaction of the caller.
|
||||||
var repository = scope.Resolve<IRepository<DatabaseLockRecord>>();
|
var repository = scope.Resolve<IRepository<DatabaseLockRecord>>();
|
||||||
var record = repository.Table.FirstOrDefault(x => x.Name == name);
|
var record = repository.Table.FirstOrDefault(x => x.Name == name);
|
||||||
|
|
||||||
@@ -67,34 +75,47 @@ namespace Orchard.TaskLease.Services {
|
|||||||
|
|
||||||
return canAcquire;
|
return canAcquire;
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex) {
|
||||||
|
Logger.Error(ex, "An error occurred while trying to acquire a lock.");
|
||||||
// This will be called at least by the IoC container when the request ends.
|
DisposeLifetimeScope();
|
||||||
public void Dispose() {
|
throw;
|
||||||
if (_isDisposed || !_isAcquired) return;
|
|
||||||
|
|
||||||
_isDisposed = true;
|
|
||||||
|
|
||||||
using (var scope = BeginLifeTimeScope(_name)) {
|
|
||||||
try {
|
|
||||||
var repository = scope.Resolve<IRepository<DatabaseLockRecord>>();
|
|
||||||
var record = repository.Get(_id);
|
|
||||||
|
|
||||||
if (record != null) {
|
|
||||||
repository.Delete(record);
|
|
||||||
repository.Flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
if (ex.IsFatal()) throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ILifetimeScope BeginLifeTimeScope(string name) {
|
// This will be called at least and at the latest by the IoC container when the request ends.
|
||||||
var scope = _lifetimeScope.BeginLifetimeScope("Orchard.Tasks.Locking.Database." + name);
|
public void Dispose() {
|
||||||
scope.Resolve<ITransactionManager>().RequireNew(IsolationLevel.ReadCommitted);
|
if (_scope == null)
|
||||||
return scope;
|
return;
|
||||||
|
|
||||||
|
if (!_isDisposed) {
|
||||||
|
_isDisposed = true;
|
||||||
|
|
||||||
|
if (_isAcquired) {
|
||||||
|
try {
|
||||||
|
var repository = _scope.Resolve<IRepository<DatabaseLockRecord>>();
|
||||||
|
var record = repository.Get(_id);
|
||||||
|
|
||||||
|
if (record != null) {
|
||||||
|
repository.Delete(record);
|
||||||
|
repository.Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
if (ex.IsFatal()) throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_scope.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ILifetimeScope EnsureLifetimeScope(string name) {
|
||||||
|
return _scope = _lifetimeScope.BeginLifetimeScope("Orchard.Tasks.Locking.Database." + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisposeLifetimeScope() {
|
||||||
|
if (_scope != null)
|
||||||
|
_scope.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user