You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#服务每周执行函数:Quartz.net示例及替代方案问询

嘿,我懂你的困扰——用每秒轮询的Timer来实现每周任务确实不够优雅,而且网上那些老的Quartz.net示例早就过时了,因为新版本已经全面切换到异步API了。下面给你一个能直接运行的Quartz入门示例,再推荐几个适合初学者的替代方案:

一、Quartz.net 3.x+ 完整入门示例

首先第一步,先安装Quartz的NuGet包:打开NuGet包管理器,搜索Quartz并安装最新稳定版,或者用命令行:

Install-Package Quartz

1. 定义你的任务类

新版本的IJob接口要求Execute方法返回Task(异步),所以我们要写异步的任务逻辑:

using Quartz;
using System.Threading.Tasks;

// 自定义任务类,实现IJob接口
public class WeeklyTaskJob : IJob
{
    // 异步执行方法,符合新版本Quartz的要求
    public async Task Execute(IJobExecutionContext context)
    {
        // 这里替换成你需要每周执行的业务逻辑
        await Task.Run(() => 
        {
            System.Console.WriteLine($"每周任务执行成功!当前时间:{System.DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            // 调用你的Function1()逻辑
        });
    }
}

2. 配置并启动调度器

接下来写调度器的初始化代码(比如在控制台程序的Main方法,或者Windows/ASP.NET Core服务的启动逻辑里):

using Quartz;
using Quartz.Impl;
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // 1. 创建调度器工厂
        var schedulerFactory = new StdSchedulerFactory();
        // 2. 获取调度器实例
        var scheduler = await schedulerFactory.GetScheduler();

        // 3. 启动调度器
        await scheduler.Start();

        // 4. 定义任务:绑定我们的WeeklyTaskJob
        var job = JobBuilder.Create<WeeklyTaskJob>()
            .WithIdentity("weeklyJob", "taskGroup") // 给任务设置唯一标识(名称+分组)
            .Build();

        // 5. 定义触发器:设置每周执行的规则,比如每周日凌晨2点
        var trigger = TriggerBuilder.Create()
            .WithIdentity("weeklyTrigger", "taskGroup")
            // 用内置方法快速定义每周调度,也可以直接写Cron表达式
            .WithSchedule(CronScheduleBuilder.WeeklyOnDayAndHourAndMinute(DayOfWeek.Sunday, 2, 0))
            // 如果你更熟悉Cron,也可以这样写:.WithCronSchedule("0 0 2 ? * SUN")
            .Build();

        // 6. 将任务和触发器绑定到调度器
        await scheduler.ScheduleJob(job, trigger);

        System.Console.WriteLine("调度器已启动,按任意键停止...");
        System.Console.ReadKey();

        // 停止调度器
        await scheduler.Shutdown();
    }
}

这段代码的好处是不需要自己做时间判断,Quartz会自动按你设置的规则触发任务,完全替代原来的轮询逻辑。

二、其他适合初学者的优雅替代方案

如果觉得Quartz有点重,还有几个更轻量化的选择:

1. Hangfire

Hangfire是一个超简单的定时任务框架,自带可视化仪表盘,对初学者非常友好。

步骤:

  • 安装NuGet包:Install-Package Hangfire + 存储包(比如内存存储Install-Package Hangfire.MemoryStorage
  • 在ASP.NET Core中配置(控制台也可以用):
// 在Program.cs里配置
var builder = WebApplication.CreateBuilder(args);

// 添加Hangfire服务,使用内存存储(生产环境建议用SQL Server等持久化存储)
builder.Services.AddHangfire(config => config.UseMemoryStorage());
builder.Services.AddHangfireServer();

var app = builder.Build();

// 启用Hangfire仪表盘(访问/hangfire路径查看任务状态)
app.UseHangfireDashboard();

// 调度每周任务:每周日2点执行
RecurringJob.AddOrUpdate("weeklyTask", () => YourWeeklyFunction(), Cron.Weekly(DayOfWeek.Sunday, 2, 0));

app.Run();

// 你的业务方法
public void YourWeeklyFunction()
{
    Console.WriteLine("Hangfire每周任务执行中...");
}

Hangfire的优势是配置简单,还能查看任务执行历史、重试失败任务,非常省心。

2. .NET 内置托管服务 + 异步Timer

如果不想用第三方库,用.NET自带的BackgroundService也能实现优雅的定时任务,避免每秒轮询:

using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

// 自定义托管服务,继承自BackgroundService
public class WeeklyHostedService : BackgroundService
{
    private Timer _timer;

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 计算第一次执行的延迟时间(下周日凌晨2点)
        var nextRunTime = GetNextRunTime();
        var initialDelay = nextRunTime - DateTime.Now;
        if (initialDelay < TimeSpan.Zero) initialDelay += TimeSpan.FromDays(7);

        // 初始化Timer,只触发一次,执行后再重新计算下一次延迟
        _timer = new Timer(async _ =>
        {
            await ExecuteWeeklyTask();
            // 更新下一次执行的延迟
            var nextDelay = GetNextRunTime() - DateTime.Now;
            if (nextDelay < TimeSpan.Zero) nextDelay += TimeSpan.FromDays(7);
            _timer.Change(nextDelay, Timeout.InfiniteTimeSpan);
        }, null, initialDelay, Timeout.InfiniteTimeSpan);

        return Task.CompletedTask;
    }

    // 计算下一次执行时间:每周日凌晨2点
    private DateTime GetNextRunTime()
    {
        var now = DateTime.Now;
        var daysUntilSunday = ((int)DayOfWeek.Sunday - (int)now.DayOfWeek + 7) % 7;
        // 如果今天是周日且已经过了2点,就顺延到下周日
        if (daysUntilSunday == 0 && now.Hour >= 2) daysUntilSunday = 7;
        return now.Date.AddDays(daysUntilSunday).AddHours(2);
    }

    // 你的每周任务逻辑
    private async Task ExecuteWeeklyTask()
    {
        Console.WriteLine($"内置托管服务任务执行:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
        await Task.CompletedTask;
    }

    // 释放资源
    public override void Dispose()
    {
        _timer?.Dispose();
        base.Dispose();
    }
}

然后在Program.cs里注册这个服务:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHostedService<WeeklyHostedService>();

var app = builder.Build();
app.Run();

这个方案完全用.NET原生功能,不需要依赖第三方库,也不会有每秒轮询的问题。


内容的提问来源于stack exchange,提问作者elemer82

火山引擎 最新活动