Asp .Net Core 系列:Asp .Net Core 集成 Hangfire+MySQL

在 .NET 或 .NET Core 应用中,若需在不依赖 Windows 服务、独立进程 的前提下实现后台处理,Hangfire 是最成熟、简单的方案之一 ------ 它可直接嵌入现有应用(如 ASP.NET Core Web 应用),无需额外部署,同时提供任务持久化、监控和重试能力。以下从 核心优势、快速集成步骤、关键用法 三方面,梳理如何用 Hangfire 实现后台处理:

一、为什么选择 Hangfire(核心优势)

  1. 零额外部署:可直接嵌入 Web 应用、控制台应用,无需单独部署 Windows 服务或计划任务;
  2. 任务持久化:支持 SQL Server、MySQL、Redis 等存储,应用重启后未执行的任务不会丢失;
  3. 可视化监控:自带 Dashboard 控制台,可实时查看任务状态(成功 / 失败 / 排队)、执行日志、重试记录;
  4. 多任务类型支持:覆盖常见后台场景(一次性任务、定时任务、周期性任务);
  5. 高可靠性:自动重试失败任务,支持任务优先级(队列区分),避免单点故障。
bash 复制代码
Install-Package Hangfire.AspNetCore
Install-Package Hangfire.MySqlStorage
cs 复制代码
    #region Hangfire与MySQL
    string connString = configuration.GetConnectionString("Hangfire")
                       ?? throw new ArgumentException("未找到Hangfire连接字符串");
    context.Services.AddHangfire(config =>
    {
        config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
              .UseSimpleAssemblyNameTypeSerializer()
              .UseRecommendedSerializerSettings();
        config.UseStorage(
                  new MySqlStorage(connString, new MySqlStorageOptions()));
    });
    context.Services.AddHangfireServer();
    context.Services.AddTransient<IBackgroundJobClient, BackgroundJobClient>();
    #endregion

    #region 定义Queues
    context.Services.AddHangfireServer(options =>
    {
        options.Queues = new[] { "maintenance-plan-overtime" };
        options.WorkerCount = 1;
    });
    #endregion
}

public override async Task OnApplicationInitializationAsync(
ApplicationInitializationContext context)
{
    await context.AddBackgroundWorkerAsync<LimitRecordWorker>();
}

public override Task OnPostApplicationInitializationAsync(ApplicationInitializationContext context)
{
    const string NAME = "HangfirePeriodicBackgroundWorkerAdapter<BackgroundJobWorker>.DoWorkAsync";
    RecurringJob.RemoveIfExists(NAME);
    return base.OnPostApplicationInitializationAsync(context);
}

如果你想使用 Hangfire Dashboard 来查看和管理后台任务,你需要在 Configure 方法中添加相应的中间件:

cs 复制代码
app.UseHangfireDashboard();

定时任务:

cs 复制代码
public class LimitRecordWorker : HangfireBackgroundWorkerBase
{
    private readonly IAbpDistributedLock _distributedLock;
    private readonly IUnitOfWorkManager _unitOfWorkManager;
    private readonly IBackgroundJobManager _backgroundJobManager;

    public LimitRecordWorker(IAbpDistributedLock distributedLock,
        IUnitOfWorkManager unitOfWorkManager,
        IConfiguration configuration,
        IBackgroundJobManager backgroundJobManager)
    {
        _distributedLock = distributedLock;
        _unitOfWorkManager = unitOfWorkManager;
        RecurringJobId = nameof(LimitRecordWorker);
        _backgroundJobManager = backgroundJobManager;
        CronExpression = configuration["Crons:LimitRecordCron"];
    }

    public override async Task DoWorkAsync(CancellationToken cancellationToken = default)
    {
        await using (var handle = await _distributedLock
            .TryAcquireAsync("LimitRecordDistributedLock", TimeSpan.FromSeconds(10)))
        {
            if (handle != null)
            {
                using (var uow = LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>().Begin())
                {
                    Log.Information("LimitRecordWorker" + DateTime.Now);

                    for (int i = 0; i <= 5; i++)
                    {
                        MaintenancePlanOverTimeArgs workProcedureLeaderArgs = new MaintenancePlanOverTimeArgs();
                        workProcedureLeaderArgs.Serial = i;
                        await _backgroundJobManager.EnqueueAsync(workProcedureLeaderArgs, delay: TimeSpan.FromHours(workProcedureLeaderArgs.OverTime % 24));
                    }
                    await uow.CompleteAsync();
                }
            }
        }
    }
}

队列服务:

cs 复制代码
    [Queue("maintenance-plan-overtime")]
    public class MaintenancePlanOverTimeJob : AsyncBackgroundJob<MaintenancePlanOverTimeArgs>, ITransientDependency
    {
        public MaintenancePlanOverTimeJob()
        {
        }

        public override async Task ExecuteAsync(MaintenancePlanOverTimeArgs args)
        {
            Log.Information("MaintenancePlanOverTimeJob:" + args.Serial + "--" + DateTime.Now);
        }
    }

    public class MaintenancePlanOverTimeArgs
    {
        public int Serial { get; set; }
        public List<Guid> EmployeeIds { get; set; }
        public Guid DepartmentId { get; set; }
        public Guid? WorkProcedureId { get; set; }
        public Guid? DeviceDetailTypeId { get; set; }
        public double OverTime { get; set; }
    }

效果:

相关推荐
一只鹿鹿鹿8 小时前
政务外网整体设计方案(PPT)
大数据·数据库·web安全·系统安全·流程图·政务
2603_965148118 小时前
社区与学习资源:从入门到精通的API选品学习路径
数据库·人工智能·python·学习·数据挖掘
for_ever_love__8 小时前
MySQL ORDER BY 排序优化:从 Using filesort 到索引有序扫描(含双路 / 单路排序原理)
java·mysql·优化·存储·by·order·filesort
AI砖家8 小时前
安全进入 Agent Loop:2027 年 Coding Agent 的决胜点
数据库·安全·codex·vibecoding
wangqiaowq8 小时前
SQL server C盘空间占满的处理
数据库·sql
文人sec8 小时前
SQL基础入门笔记 | 从零基础到掌握核心查询语句
数据库·笔记·sql
数字新视界8 小时前
机房动环监控提升运维效率
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
SelectDB技术团队9 小时前
冷热分层从建到验:Storage Policy 创建、表级与分区级绑定、SHOW TABLETS 验证的完整命令
大数据·数据库·elasticsearch·搜索引擎·数据分析·apache doris·冷热分层
lambo mercy11 小时前
Day3:结构化输出
java·数据库·oracle
派小心.11 小时前
小程序分享链路中来源参数的传递校验
大数据·前端·数据库·人工智能·小程序·数据分析