Skip to content

Commit 4e8040f

Browse files
committed
Don't commit external transaction in BackgroundJobStateChanger
1 parent b95d29e commit 4e8040f

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

Diff for: src/Hangfire.Core/States/BackgroundJobStateChanger.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,10 @@ public IState ChangeState(StateChangeContext context)
160160
}
161161
}
162162

163-
transaction.Commit();
163+
if (context.Transaction == null)
164+
{
165+
transaction.Commit();
166+
}
164167

165168
context.ProcessedJob = backgroundJob;
166169
return appliedState;

Diff for: tests/Hangfire.Core.Tests/Mocks/StateChangeContextMock.cs

+4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ public StateChangeContextMock()
2626
() => new StateChangeContext(
2727
Storage.Object,
2828
Connection.Object,
29+
Transaction?.Object,
2930
BackgroundJobId,
3031
NewState.Object,
3132
ExpectedStates,
3233
DisableFilters,
34+
CompleteJob?.Object,
3335
CancellationToken,
3436
EmptyProfiler.Instance,
3537
ServerId,
@@ -38,6 +40,8 @@ public StateChangeContextMock()
3840

3941
public Mock<JobStorage> Storage { get; set; }
4042
public Mock<IStorageConnection> Connection { get; set; }
43+
public Mock<JobStorageTransaction> Transaction { get; set; }
44+
public Mock<IFetchedJob> CompleteJob { get; set; }
4145
public string BackgroundJobId { get; set; }
4246
public Mock<IState> NewState { get; set; }
4347
public IEnumerable<string> ExpectedStates { get; set; }

Diff for: tests/Hangfire.Core.Tests/States/BackgroundJobStateChangerFacts.cs

+39
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,45 @@ public void ChangeState_DoesNotInvokeApplyStateFilters_WhenFiltersDisabled()
495495
_transaction.Verify(x => x.Commit());
496496
}
497497

498+
[Fact]
499+
public void ChangeState_WithTransaction_PassesTheGivenTransaction_AndDoesNotCommitTheImplicitOne()
500+
{
501+
_context.Transaction = new Mock<JobStorageTransaction>();
502+
var stateChanger = CreateStateChanger();
503+
504+
stateChanger.ChangeState(_context.Object);
505+
506+
_stateMachine.Verify(x => x.ApplyState(It.Is<ApplyStateContext>(
507+
ctx => ctx.Transaction == _context.Transaction.Object)));
508+
509+
_connection.Verify(x => x.CreateWriteTransaction(), Times.Never);
510+
_transaction.Verify(x => x.Commit(), Times.Never);
511+
}
512+
513+
[Fact]
514+
public void ChangeState_WithTransaction_DoesNotCommitAndDoesNotDisposeTheExplicitTransaction()
515+
{
516+
_context.Transaction = new Mock<JobStorageTransaction>();
517+
var stateChanger = CreateStateChanger();
518+
519+
stateChanger.ChangeState(_context.Object);
520+
521+
_context.Transaction.Verify(x => x.Commit(), Times.Never);
522+
_context.Transaction.Verify(x => x.Dispose(), Times.Never);
523+
}
524+
525+
[Fact]
526+
public void ChangeState_WithTransaction_AcquiresATransactionLevelLockInstead()
527+
{
528+
_context.Transaction = new Mock<JobStorageTransaction>();
529+
var stateChanger = CreateStateChanger();
530+
531+
stateChanger.ChangeState(_context.Object);
532+
533+
_context.Transaction.Verify(x => x.AcquireDistributedLock($"job:{JobId}:state-lock", It.IsAny<TimeSpan>()));
534+
_connection.Verify(x => x.AcquireDistributedLock(It.IsAny<string>(), It.IsAny<TimeSpan>()), Times.Never);
535+
}
536+
498537
private BackgroundJobStateChanger CreateStateChanger()
499538
{
500539
return new BackgroundJobStateChanger(_filterProvider.Object, _stateMachine.Object);

0 commit comments

Comments
 (0)