【问题标题】:Quartz.net scheduler gets garbage collectedQuartz.net 调度程序收集垃圾
【发布时间】:2020-03-26 08:45:27
【问题描述】:

目前有 12 个作业在使用quartz.net 运行。

前 10 个作业需要每 30 分钟运行一次。 后 2 个作业需要每 3 分钟运行一次。

问题在于每 3 分钟运行的 2 个作业完成后。程序停止工作。它不会崩溃,控制台窗口仍在响应,但应用程序不再触发作业。

我认为这是因为调度程序收集了垃圾。有人对此有解决方案吗?

开始异步:

public async Task StartAsync(CancellationToken cancellationToken)
{
    var scheduler = await GetScheduler();
    await scheduler.Start();

    await scheduler.ScheduleJob(GetAbsenceJob(), GetDefaultTrigger(nameof(AbsenceJob)));
    await scheduler.ScheduleJob(GetAddressJob(), GetDefaultTrigger(nameof(AddressJob)));
    await scheduler.ScheduleJob(GetCustomerJob(), GetDefaultTrigger(nameof(CustomerJob)));
    await scheduler.ScheduleJob(GetDriverJob(), GetDefaultTrigger(nameof(DriverJob)));
    await scheduler.ScheduleJob(GetPlanCombJob(), GetDefaultTrigger(nameof(PlanCombJob)));
    await scheduler.ScheduleJob(GetPlanGroupJob(), GetDefaultTrigger(nameof(PlanGroupJob)));
    await scheduler.ScheduleJob(GetSupplierJob(), GetDefaultTrigger(nameof(SupplierJob)));
    await scheduler.ScheduleJob(GetTrailerJob(), GetDefaultTrigger(nameof(TrailerJob)));
    await scheduler.ScheduleJob(GetTransportTypeJob(), GetDefaultTrigger(nameof(TransportTypeJob)));
    await scheduler.ScheduleJob(GetVehicleJob(), GetDefaultTrigger(nameof(VehicleJob)));

    await scheduler.ScheduleJob(GetImportFilesJob(), GetImportTrigger(nameof(ImportFilesJob)));
    await scheduler.ScheduleJob(GetExtractFilesJob(), GetImportTrigger(nameof(ExtractFilesJob)));

}

获取计划

private static async Task<IScheduler> GetScheduler()
{
    var props = new NameValueCollection {
        { "quartz.threadPool.threadCount",      "20" },
        { "quartz.jobStore.misfireThreshold",   "60000" },
        { "quartz.serializer.type",             "binary" },
        { "quartz.scheduler.instanceName",      "SynchroScheduler"},
        { "quartz.jobStore.type",               "Quartz.Simpl.RAMJobStore, Quartz" },
        { "quartz.threadPool.type",             "Quartz.Simpl.SimpleThreadPool, Quartz" }
    };
    var factory = new StdSchedulerFactory(props);
    var scheduler = await factory.GetScheduler();

    return scheduler;
}

编辑:

服务是如何启动的:

var host = new HostBuilder()
                .ConfigureHostConfiguration(configHost =>
                {
                    configHost.SetBasePath(Directory.GetCurrentDirectory());
                    configHost.AddJsonFile(Text.Hostsettings, optional: true);
                    configHost.AddEnvironmentVariables(prefix: Text.Prefix);
                    configHost.AddCommandLine(args);
                })
                .ConfigureAppConfiguration((hostContext, configApp) =>
                {
                    configApp.SetBasePath(Directory.GetCurrentDirectory());
                    configApp.AddJsonFile(Text.Appsettings, optional: true);
                    configApp.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true);
                    configApp.AddEnvironmentVariables(prefix: Text.Prefix);
                    configApp.AddCommandLine(args);
                })
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddLogging();
                    services.Configure<SynchroDbOptions>(hostContext.Configuration.GetSection("SynchoDbOptions"));
                    services.AddHostedService<DbSyncService>();
                })
                .ConfigureLogging((hostContext, configLogging) =>
                {
                    configLogging.AddConfiguration(hostContext.Configuration.GetSection("Logging"));
            configLogging.AddConsole();

        })
        .UseConsoleLifetime()
        .Build();

host.RunAsync();

【问题讨论】:

    标签: c# cron quartz.net cron-task


    【解决方案1】:

    是的,你是对的。 ScheduleJob 只是注册作业,它不会等待它执行。在某个时候,垃圾收集器会出现并回收内存,我记得有一个终结器可以取消调度任何作业。因此,您需要将您计划的 IScheduler 实例存储到其中。

    一种选择是将IScheduler 返回给调用者,以便他们决定如何存储它:

    public async Task<IScheduler> StartAsync(CancellationToken cancellationToken)
    {
        ...
        ...
        return scheduler;
    }
    

    另一种方法是让您的实例方法将其存储在成员变量中,并让类管理调度程序的生命周期。根据您的 cmets,这可能是最好的方法。

    由于您的类 DBSyncService 已注册为服务,因此只需添加一个成员变量:

    private IScheduler _scheduler;
    

    并将其设置为StartAsync,这意味着调度程序的生命周期由服务的生命周期控制,而服务的生命周期又由服务容器的生命周期管理。

    【讨论】:

    • 感谢您的回复。我可以遵循逻辑,但是我有一个问题。 StartAsync 功能使用 HostBuilder 在不同的文件中启动。我已经编辑了我的问题,您能否看看我将如何捕获调度程序?
    • @BjornPijpops - 显示服务如何启动的代码没有调用原始示例中的任何一种方法,因此很难解释如何捕获调度程序。您能否将IScheduler 注册为一项服务,以便在应用程序运行期间保持活动状态?
    • 因此,您告诉我将返回值更改为的 StartAsync 方法是不可能的。该方法继承自 IHostedService,并且该服务只有异步任务 StartAsync 和异步任务 StartAsync。因此我不可能返回调度器
    • @BjornPijpops - 所以听起来你需要做的是将DbSyncService 存储为成员变量IScheduler。
    • 似乎很有魅力!感谢您的快速响应!
    猜你喜欢
    • 1970-01-01
    • 2011-01-21
    • 2011-01-06
    • 1970-01-01
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    相关资源
    最近更新 更多