wanshenmean
8 小时以前 96adc295cb04fd135d63d3a907f2732274f90965
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/JobFactory.cs
@@ -19,6 +19,7 @@
using Quartz.Spi;
using Quartz;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -28,7 +29,7 @@
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// Job注入
    /// Job注入工厂,管理 Job 实例的 DI 作用域生命周期
    /// </summary>
    public class JobFactory : IJobFactory
    {
@@ -38,48 +39,71 @@
        private readonly IServiceProvider _serviceProvider;
        /// <summary>
        /// Job 实例与对应的 DI 作用域映射,用于在 ReturnJob 时正确释放资源
        /// </summary>
        private readonly ConcurrentDictionary<IJob, IServiceScope> _scopes = new();
        /// <summary>
        /// Job注入
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <param name="serviceProvider">服务提供者</param>
        public JobFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        /// <summary>
        /// 实现接口Job
        /// 创建 Job 实例,并为每个 Job 创建独立的 DI 作用域
        /// </summary>
        /// <param name="bundle"></param>
        /// <param name="scheduler"></param>
        /// <returns></returns>
        /// <param name="bundle">触发器触发上下文</param>
        /// <param name="scheduler">调度器实例</param>
        /// <returns>Job 实例</returns>
        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            try
            {
                if (App.ExpDateTime != null && (DateTime.Now - App.ExpDateTime.GetValueOrDefault()).Seconds > 0)
                // 验证有效期,使用 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 new Exception(ex.Message);
                throw;
            }
        }
        /// <summary>
        /// Job注入
        /// 释放 Job 实例及其关联的 DI 作用域
        /// </summary>
        /// <param name="job"></param>
        /// <param name="job">待释放的 Job 实例</param>
        public void ReturnJob(IJob job)
        {
            IDisposable? disposable = job as IDisposable;
            disposable?.Dispose();
            // 先释放关联的 DI 作用域(包括其中所有 Scoped 服务)
            if (_scopes.TryRemove(job, out IServiceScope? scope))
            {
                scope.Dispose();
            }
            // 再释放 Job 本身
            (job as IDisposable)?.Dispose();
        }
    }
}