#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(); } } }