-
-
Save Antaris/9c3c097d31a90da279e3e6d78497a369 to your computer and use it in GitHub Desktop.
using System; | |
using System.Collections.Generic; | |
using Microsoft.Extensions.DependencyInjection; | |
using Quartz; | |
using Quartz.Spi; | |
public class ServiceProviderJobFactory : IJobFactory | |
{ | |
private readonly IServiceProvider _rootServiceProvider; | |
private ConcurrentDictionary<Type, IServiceScope> _scopes = new ConcurrentDictionary<Type, IServiceScope>(); | |
public ServiceProviderJobFactory(IServiceProvider rootServiceProvider) | |
{ | |
_rootServiceProvider = rootServiceProvider ?? throw new ArgumentNullException(rootServiceProvider); | |
} | |
public IJob NewJob(TriggerFireBundle bundle, IScheduler scheduler) | |
{ | |
var jobType = bundle.JobDetail.JobType; | |
// MA - Generate a scope for the job, this allows the job to be registered | |
// using .AddScoped<T>() which means we can use scoped dependencies | |
// e.g. database contexts | |
var scope = _scopes.GetOrAdd(jobType, t => _rootServiceProvider.CreateScope()); | |
return (IJob)scope.ServiceProvider.GetRequiredService(jobType); | |
} | |
public void ReturnJob(IJob job) | |
{ | |
var jobType = job?.GetType(); | |
if (job != null && _scopes.TryGetValue(jobType, out var scope) | |
{ | |
// MA - Dispose of the scope, which disposes of the job's dependencies | |
scope.Dispose(); | |
// MA - Remove the scope so the next time the job is resolved, | |
// we can get a new job instance | |
_scopes.TryRemove(jobType, out _); | |
} | |
} | |
} |
How about https://github.com/AndyPook/QuartzHostedService/blob/master/QuartzHostedService/ScopedJobFactory.cs as another alternative?
Tightly associates the scope with the job, avoids the dictionary...
Why the factory pattern must be used? Are there other ways to achieve the same result in a much cleaner way?
Quartz now has a baked in solution using their new Quartz.Extensions.Hosting
package
https://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/
Quartz now has a baked in solution using their new
Quartz.Extensions.Hosting
packagehttps://andrewlock.net/using-quartz-net-with-asp-net-core-and-worker-services/
Thank you, I literally have found that blog at the same time you wrote me :)
I checked the provided link about Quartz.Extensions.Hosting but what happens If I need to create jobs based on some information received after the worker service is started.
Let's say I have a BackgroundService hosted in a windows service and this windows service is responsible for creating new jobs based on some information received from other applications, let's say, a desktop application; unfortunately the above link about Quartz.Extensions.Hosting, does not help at all. Please correct me if I'm wrong.
Thanks, AndyPook for the provided sample.
One problem with this design is that the cache key type is the
Type
instance, which means overlapping jobs would resolve to the sameIServiceScope
instance, which could lead to unexpected disposal of services in subsequent jobs if they do overlap.Alternatively, instead of using the
Type
as a cache key, use the job instance itself: