#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 命名空间:WIDESEAWCS_QuartzJob
* 创建者:胡童庆
* 创建时间:2024/8/2 16:13:36
* 版本:V1.0.0
* 描述:Job工厂类
*
* ----------------------------------------------------------------
* 修改人:
* 修改时间:
* 版本:V1.0.1
* 修改说明:
*
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using Microsoft.Extensions.DependencyInjection;
using Quartz.Spi;
using Quartz;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
namespace WIDESEAWCS_QuartzJob
{
///
/// Job注入工厂,管理 Job 实例的 DI 作用域生命周期
///
public class JobFactory : IJobFactory
{
///
/// 注入反射获取依赖对象
///
private readonly IServiceProvider _serviceProvider;
///
/// Job 实例与对应的 DI 作用域映射,用于在 ReturnJob 时正确释放资源
///
private readonly ConcurrentDictionary _scopes = new();
///
/// Job注入
///
/// 服务提供者
public JobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
///
/// 创建 Job 实例,并为每个 Job 创建独立的 DI 作用域
///
/// 触发器触发上下文
/// 调度器实例
/// Job 实例
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
// 验证有效期,使用 TotalSeconds 避免 .Seconds 取模导致间歇性判断错误
if (App.ExpDateTime != null && (DateTime.Now - App.ExpDateTime.GetValueOrDefault()).TotalSeconds > 0)
{
throw new InvalidOperationException($"验证错误");
}
// 为每个 Job 创建独立的 DI 作用域,确保 Scoped 服务正确释放
IServiceScope serviceScope = _serviceProvider.CreateScope();
IJob? job = serviceScope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
if (job == null)
{
// Job 解析失败时立即释放作用域,避免泄漏
serviceScope.Dispose();
throw new InvalidOperationException($"无法解析 Job 类型: {bundle.JobDetail.JobType.Name}");
}
// 保存 scope 引用,以便 ReturnJob 时释放
_scopes[job] = serviceScope;
return job;
}
catch (Exception ex)
{
Console.Out.WriteLine(ex.ToString());
throw;
}
}
///
/// 释放 Job 实例及其关联的 DI 作用域
///
/// 待释放的 Job 实例
public void ReturnJob(IJob job)
{
// 先释放关联的 DI 作用域(包括其中所有 Scoped 服务)
if (_scopes.TryRemove(job, out IServiceScope? scope))
{
scope.Dispose();
}
// 再释放 Job 本身
(job as IDisposable)?.Dispose();
}
}
}