Комментарии 7
Я ользовался такой реализацией, но суть таже
Spoiler header
public class MicrosoftDependencyInjectionJobFactory : IJobFactory
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
private readonly IServiceProvider _container;
/// <summary>
/// .ctor
/// </summary>
/// <param name="container"></param>
public MicrosoftDependencyInjectionJobFactory(IServiceProvider container)
{
_container = container;
}
/// <inheritdoc />
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
// Отлавливаем ошибки получения сервиса из DI
try
{
var job = _container.GetService(bundle.JobDetail.JobType) as IJob;
if (job != null)
{
return job;
}
else
{
var exception = new Exception($"Can't cast {bundle.JobDetail.JobType} to {typeof(IJob)}");
Logger.Error(exception);
throw exception;
}
}
catch (Exception exception)
{
Logger.Error(exception, $"Can't get {bundle.JobDetail.JobType} through DI");
throw;
}
}
/// <inheritdoc />
public void ReturnJob(IJob job)
{
var disposable = job as IDisposable;
disposable?.Dispose();
}
}
Вы неправильно используете IServiceScope — вы его уничтожаете сразу после создания, не дождавшись выполнения задачи. А используя ActivatorUtilities из Microsoft.Extensions.DependencyInjection можно избежать регистрации самих задач в контейнере.
Код
public class JobFactory : IJobFactory
{
private readonly IServiceProvider _provider;
public JobFactory(IServiceProvider provider)
{
_provider = provider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return new JobWrapper(_provider, bundle.JobDetail.JobType);
}
public void ReturnJob(IJob job)
{
(job as IDisposable)?.Dispose();
}
}
public class JobWrapper : IJob, IDisposable
{
private readonly IServiceScope _serviceScope;
private readonly IJob _job;
public JobWrapper(IServiceProvider serviceProvider, Type jobType)
{
_serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
_job = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, jobType) as IJob;
}
public Task Execute(IJobExecutionContext context)
{
return _job.Execute(context);
}
public void Dispose()
{
_serviceScope.Dispose();
}
}
public class DataJob : IJob
{
private readonly IEmailSender _emailSender;
public DataJob(IEmailSender emailSender)
{
_emailSender = emailSender;
}
public async Task Execute(IJobExecutionContext context)
{
await _emailsender.SendEmailAsync("example@gmail.com", "example", "hello");
}
}
Нет ли ничего плохого в том что у вас host.Run() запускается после уничтожения scope?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Quartz в ASP.NET Core