Describe the bug
Quartz job that implements IDisposable is disposed twice when using DependencyInjectionJobFactory with CreateScope enabled (e.g. via UseMicrosoftDependencyInjectionScopedJobFactory extension method).
This shouldn't be a big problem, because properly implemented Dispose can be called multiple times safely according to Framework Design Guidelines. But still, it's something that could be improved.
The reason the duplicate disposal happens is because the job is first disposed when disposing the DI scope and then explicitly by ScopedJob:
|
public void Dispose() |
|
{ |
|
scope.Dispose(); |
|
(innerJob as IDisposable)?.Dispose(); |
|
} |
Version used
3.2.4
To Reproduce
Prepare a test project:
dotnet new nunit --name QuartzTests
cd QuartzTests
dotnet add package Quartz.Extensions.DependencyInjection --version 3.2.4
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Logging
Set UnitTest1.cs to:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NUnit.Framework;
using Quartz;
namespace QuartzTests
{
public class Tests
{
[Test]
public async Task Test1()
{
var services = new ServiceCollection();
services.AddLogging();
services.AddQuartz(cfg =>
{
cfg.UseMicrosoftDependencyInjectionScopedJobFactory();
cfg.ScheduleJob<MyJob>(t => { });
});
var sp = services.BuildServiceProvider();
var schedulerFactory = sp.GetRequiredService<ISchedulerFactory>();
var scheduler = await schedulerFactory.GetScheduler();
await scheduler.Start();
await scheduler.Shutdown(waitForJobsToComplete: true);
Assert.AreEqual(1, MyJob.ExecuteCount);
// FAILS, ACTUAL = 2
Assert.AreEqual(1, MyJob.DisposeCount);
}
class MyJob : IJob, IDisposable
{
static int _executeCount;
static int _disposeCount;
public Task Execute(IJobExecutionContext context)
{
Interlocked.Increment(ref _executeCount);
return Task.CompletedTask;
}
public void Dispose()
{
Interlocked.Increment(ref _disposeCount);
}
public static int ExecuteCount => _executeCount;
public static int DisposeCount => _disposeCount;
}
}
}
Expected behavior
Job should be disposed only once.
Describe the bug
Quartz job that implements
IDisposableis disposed twice when usingDependencyInjectionJobFactorywithCreateScopeenabled (e.g. viaUseMicrosoftDependencyInjectionScopedJobFactoryextension method).This shouldn't be a big problem, because properly implemented
Disposecan be called multiple times safely according to Framework Design Guidelines. But still, it's something that could be improved.The reason the duplicate disposal happens is because the job is first disposed when disposing the DI scope and then explicitly by
ScopedJob:quartznet/src/Quartz.Extensions.DependencyInjection/Simpl/MicrosoftDependencyInjectionJobFactory.cs
Lines 70 to 74 in 5411524
Version used
3.2.4
To Reproduce
Prepare a test project:
Set UnitTest1.cs to:
Expected behavior
Job should be disposed only once.