ABP VNext + Quartz.NET vs Hangfire:灵活调度与任务管理

ABP VNext + Quartz.NET vs Hangfire:灵活调度与任务管理 🚀


📚 目录

  • ABP VNext + Quartz.NET vs Hangfire:灵活调度与任务管理 🚀
    • ✨ TL;DR
    • 🛠 环境与依赖
    • 🔧 Quartz.NET 在 ABP 中接入
      • 1. 安装与模块依赖
      • 2. 集中配置持久化、序列化与集群
      • 3. 服务注册、作业定义与重试策略
      • 4. 业务层动态调度 🔄
    • 🔧 Hangfire 在 ABP 中接入
      • 1. 安装与模块依赖
      • 2. 作业定义与触发 🎯
    • 🔒 高可用与集群部署对比
    • ⚡ 性能与可视化对比
    • 💡 最佳实践


✨ TL;DR

  • 通过 ABP VNext 的配置管道,使用 PreConfigure<AbpQuartzOptions>Configure<AbpHangfireOptions>,实现对 Quartz.NET 与 Hangfire 的零侵入集成
  • 对比两者在持久化存储集群模式作业定义可视化监控等方面的核心差异
  • 多实例高可用场景下的选型建议落地最佳实践

背景与动机
在微服务架构中,定时与异步任务无处不在。ABP 自带的 Background Job 模块适合中小规模场景;但当你需要精细调度策略多节点容错可视化监控时,Quartz.NET 与 Hangfire 是首选方案。本文结合 ABP VNext 最佳实践,系统对比二者接入方式、集群部署与运维复杂度,助你快速选型并落地。


🛠 环境与依赖

  • 平台版本:.NET 7/8 + ABP VNext 7.x/8.x

  • 核心 NuGet 包

    abp add-package Volo.Abp.BackgroundJobs.Quartz
    abp add-package Volo.Abp.BackgroundJobs.HangFire
    
  • 持久化存储:SQL Server / Redis(可选)


🔧 Quartz.NET 在 ABP 中接入

1. 安装与模块依赖

abp add-package Volo.Abp.BackgroundJobs.Quartz
[DependsOn(typeof(AbpBackgroundJobsQuartzModule))]
public class MyAppQuartzModule : AbpModule
{// ...
}

2. 集中配置持久化、序列化与集群

public override void PreConfigureServices(ServiceConfigurationContext context)
{var configuration = context.Services.GetConfiguration();var appName       = configuration["App:Name"] ?? "MyApp";PreConfigure<AbpQuartzOptions>(options =>{options.Properties = new NameValueCollection{// 调度器实例名与自动生成实例ID,保证同库多应用/多节点隔离["quartz.scheduler.instanceName"] = appName,["quartz.scheduler.instanceId"]   = "AUTO",      // ADO.NET JobStore 与表前缀["quartz.jobStore.type"]          = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",["quartz.jobStore.tablePrefix"]   = "QRTZ_",["quartz.jobStore.dataSource"]    = "default",// 数据源配置["quartz.dataSource.default.provider"]       = "SqlServer",["quartz.dataSource.default.connectionString"] = configuration.GetConnectionString("Default")!,// JSON 序列化["quartz.serializer.type"]                  = "json",// SQL Server 驱动委派["quartz.jobStore.driverDelegateType"]      = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz",// 集群模式开关["quartz.jobStore.clustered"]               = "true",   // 配置集群模式// 心跳检查间隔与错过触发容忍阈值(单位:毫秒)["quartz.jobStore.clusterCheckinInterval"]  = "20000",["quartz.jobStore.misfireThreshold"]        = "60000"};});
}

说明:在集群模式下,quartz.jobStore.clustered=true 用于开启数据库锁与心跳机制;quartz.scheduler.instanceId=AUTO 确保每个节点拥有唯一 ID。

3. 服务注册、作业定义与重试策略

public override void ConfigureServices(ServiceConfigurationContext context)
{// 注入作业实现context.Services.AddTransient<SampleJob>();// 注册 Quartz 并调度作业context.Services.AddQuartz(q =>{q.UseMicrosoftDependencyInjectionJobFactory();q.ScheduleJob<SampleJob>(trigger => trigger.WithIdentity("SampleJobTrigger").StartNow().WithCronSchedule("0/5 * * * * ?")); // 每 5 秒执行一次});// 托管服务:在停止时等待作业完成context.Services.AddQuartzHostedService(opt => opt.WaitForJobsToComplete = true);// 全局重试策略(单位:毫秒)Configure<AbpBackgroundJobQuartzOptions>(opts =>{opts.RetryCount               = 3;opts.RetryIntervalMillisecond = (int)TimeSpan.FromSeconds(10).TotalMilliseconds;});
}
public class SampleJob : IJob, ITransientDependency
{public Task Execute(IJobExecutionContext context){Console.WriteLine($"[Quartz] Executed at {DateTime.Now:O}");return Task.CompletedTask;}
}

4. 业务层动态调度 🔄

public class ScheduleService : ITransientDependency
{private readonly IQuartzScheduleJobManager _jobManager;public ScheduleService(IQuartzScheduleJobManager jobManager) =>_jobManager = jobManager;public async Task ScheduleSampleJobAsync(){await _jobManager.ScheduleAsync<SampleJob>(job => job.WithIdentity("DynamicSampleJob").WithDescription("由业务层动态调度"),trigger => trigger.StartNow().WithSimpleSchedule(x => x.WithIntervalInSeconds(15).RepeatForever()));}
}

优化提示:也可使用 AbpQuartzOptions.Configurator API 进行链式配置,避免手动拼写属性名,语义更清晰。


🔧 Hangfire 在 ABP 中接入

1. 安装与模块依赖

abp add-package Volo.Abp.BackgroundJobs.HangFire
[DependsOn(typeof(AbpBackgroundJobsHangfireModule))]
public class MyAppHangfireModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){var configuration = context.Services.GetConfiguration();// 持久化存储context.Services.AddHangfire(cfg =>cfg.UseSqlServerStorage(configuration.GetConnectionString("Default")));// 服务器选项:并发工作数与队列Configure<AbpHangfireOptions>(options =>{options.ServerOptions = new BackgroundJobServerOptions{WorkerCount = 20,Queues      = new[] { "default" }};});}public override void OnApplicationInitialization(ApplicationInitializationContext context){var app = context.GetApplicationBuilder();// 挂载 Dashboard 并使用 ABP 授权过滤app.UseAbpHangfireDashboard("/hangfire", opts =>{opts.AsyncAuthorization = new[]{new AbpHangfireAuthorizationFilter("Hangfire.View")};});  // 建议使用 ABP 授权过滤app.UseConfiguredEndpoints();// 周期任务示例var recurringManager = context.ServiceProvider.GetRequiredService<IRecurringJobManager>();recurringManager.AddOrUpdate("HelloJobRecurring",Job.FromExpression<HelloJob>(job => job.ExecuteAsync(new HelloJobArgs { Name = "ABP" })),Cron.Minutely);}
}

2. 作业定义与触发 🎯

public class HelloJobArgs { public string Name { get; set; } }public class HelloJob : AsyncBackgroundJob<HelloJobArgs>, ITransientDependency
{public override Task ExecuteAsync(HelloJobArgs args){Console.WriteLine($"[Hangfire] Hello, {args.Name}, at {DateTime.Now:O}");return Task.CompletedTask;}
}public class SomeService : ITransientDependency
{private readonly IBackgroundJobManager _jobManager;public SomeService(IBackgroundJobManager jobManager) => _jobManager = jobManager;public Task RunAsync() =>_jobManager.EnqueueAsync<HelloJob, HelloJobArgs>(new HelloJobArgs { Name = "World" });
}

🔒 高可用与集群部署对比

Hangfire Cluster
Dequeue/Execute
Dequeue/Execute
Hangfire Storage DB
Client Enqueue
Server 1
Server 2
Quartz.NET Cluster
Poll & Lock
Poll & Lock
Grant & Trigger
Scheduler Node 1
Quartz JobStore DB
Scheduler Node 2

说明:Quartz 通过轮询 + 锁竞争实现集群;Hangfire 则由客户端入队,任意 Server 拉取执行。

特性Quartz.NETHangfire
集群模式quartz.jobStore.clustered=true + clusterCheckinInterval + misfireThreshold,DB 锁与心跳协调执行多服务器共享存储,GUID 生成唯一 ServerId,无需额外配置
故障切换锁超时后其他节点接管;错过触发由 misfireThreshold 控制重调度延迟心跳停止后,未完成任务按 InvisibilityTimeout 重新入队并重试
持久化存储支持ADO.NET(SQL/Oracle/PostgreSQL)、MongoDB、Redis 等SQL Server、Redis、MongoDB 等;多种官方 & 社区扩展
可视化管理第三方 Dashboard:SilkierQuartz、QuartzDesk 等内置 Dashboard + ABP 授权过滤,支持失败重试与队列监控

⚡ 性能与可视化对比

  • 启动延迟:Quartz 需初始化 Scheduler 与 JobStore,冷启动略慢;Hangfire 支持延迟加载 Server,启动体验更快。

  • 吞吐能力:视硬件、网络与存储配置而定,建议使用 Benchmark.NET 进行真实测量

  • Dashboard 功能

    • Quartz + SilkierQuartz:需额外部署,支持作业历史与触发器管理;
    • Hangfire:开箱即用,支持自定义队列、重试策略与并发监控。

💡 最佳实践

  1. 零侵入抽象:业务层仅依赖 AsyncBackgroundJob<TArgs>IBackgroundJobManager/IQuartzScheduleJobManager,可测试性与可切换性俱佳。

  2. 集中配置管道:通过 PreConfigure<AbpQuartzOptions>Configure<AbpHangfireOptions> 统一管理持久化、集群、队列与重试策略。

  3. 依赖注入:作业类型实现 ITransientDependency 即可自动注册;Quartz 场景下如需显式注册,可 AddTransient<SampleJob>()

  4. 安全与监控

    • Quartz:结合 Prometheus Exporter 与 SilkierQuartz 构建可观测平台;
    • Hangfire:使用 ABP 授权过滤(AbpHangfireAuthorizationFilter)保护 Dashboard。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/94166.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/94166.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[硬件电路-148]:数字电路 - 什么是CMOS电平、TTL电平?还有哪些其他电平标准?发展历史?

1. CMOS电平定义&#xff1a; CMOS&#xff08;Complementary Metal-Oxide-Semiconductor&#xff09;电平基于互补金属氧化物半导体工艺&#xff0c;由PMOS和NMOS晶体管组成。其核心特点是低功耗、高抗干扰性和宽电源电压范围&#xff08;通常为3V~18V&#xff09;。关键参数&…

0基礎網站開發技術教學(二) --(前端篇 2)--

書接上回說到的前端3種主語言以及其用法&#xff0c;這期我們再來探討一下javascript的一些編碼技術。 一) 自定義函數 假如你要使用一個功能&#xff0c;正常來說直接敲出來便可。可如果這個功能你要用不止一次呢?難道你每次都敲出來嗎?這個時侯&#xff0c;就要用到我們的自…

前端 拼多多4399笔试题目

拼多多 3 选择题 opacity|visibity|display区别 在CSS中&#xff0c;opacity: 0 和 visibility: hidden 都可以让元素不可见&#xff0c;但它们的行为不同&#xff1a; ✅ opacity: 0&#xff08;透明度为0&#xff09; 元素仍然占据空间&#xff08;不移除文档流&#xff0…

数琨创享:全球汽车高端制造企业 QMS质量管理平台案例

01.行业领军者的质量升级使命在全球汽车产业链加速升级的浪潮中&#xff0c;质量管控能力已成为企业核心竞争力的关键。作为工信部认证的制造业单项冠军示范企业&#xff0c;万向集团始终以“全球制造、全球市场、做行业领跑者”为战略愿景。面对奔驰、宝马、大众等“9N”高端客…

GaussDB 约束的使用举例

1 not null 约束not null 约束强制列不接受 null 值。not null 约束强制字段始终包含值。这意味着&#xff0c;如果不向字段添加值&#xff0c;就无法插入新记录或者更新记录。GaussDB使用pg_get_tabledef()函数获取customers表结构&#xff0c;如&#xff1a;csdn> set sea…

自动驾驶中的传感器技术13——Camera(4)

1、自驾Camera开发的方案是否归一化对于OEM&#xff0c;或者自驾方案商如Mobileye如果进行Camera的开发&#xff0c;一般建议采用Tesla的系统化最优方案&#xff0c;所有Camera统一某个或者某两个MP设计&#xff08;增加CIS议价权&#xff0c;减少Camera PCBA的设计维护数量&am…

开源利器:glTF Compressor——高效优化3D模型的终极工具

在3D图形开发领域,glTF(GL Transmission Format)已成为Web和移动端3D内容的通用标准。然而,3D模型的文件体积和纹理质量往往面临权衡难题。Shopify最新开源的glTF Compressor工具,为开发者提供了一套精细化、自动化的解决方案,让3D模型优化既高效又精准。本文将深入解析这…

LeetCode Hot 100,快速学习,不断更

工作做多了有时候需要回归本心&#xff0c;认真刷题记忆一下算法。那就用我这练习时长两年半的代码农民工来尝试着快速解析LeetCode 100吧 快速解析 哈希 1. 两数之和 - 力扣&#xff08;LeetCode&#xff09; 这题很简单啊&#xff0c;思路也很多 1. 暴力搜索&#xff0c;…

MySQL的子查询:

目录 子查询的相关概念&#xff1a; 子查询的分类&#xff1a; 角度1&#xff1a; 单行子查询&#xff1a; 单行比较操作符&#xff1a; 子查询的空值情况&#xff1a; 多行子查询&#xff1a; 多行比较操作符&#xff1a; ANY和ALL的区别&#xff1a; 子查询为空值的…

Python批处理深度解析:构建高效大规模数据处理系统

引言&#xff1a;批处理的现代价值在大数据时代&#xff0c;批处理&#xff08;Batch Processing&#xff09; 作为数据处理的核心范式&#xff0c;正经历着复兴。尽管实时流处理备受关注&#xff0c;但批处理在数据仓库构建、历史数据分析、报表生成等场景中仍不可替代。Pytho…

是德科技的BenchVue和纳米软件的ATECLOUD有哪些区别?

是德科技的BenchVue和纳米软件的ATECLOUD虽然都是针对仪器仪表测试的软件&#xff0c;但是在功能设计、测试场景、技术架构等方面有着明显的差异。BenchVue&#xff08;是德科技&#xff09;由全球领先的测试测量设备供应商开发&#xff0c;专注于高端仪器控制与数据分析&#…

线上redis的使用

一.String1.缓存玩家单个数据&#xff0c;但是我觉得还是用hash好2.结合过期时间&#xff0c;比如:某个东西结算了&#xff0c;redis记录一下&#xff0c;并设置过期时间3.分布式锁二.Hash1.缓存一个单位的数据&#xff0c;比如&#xff1a;联盟信息2.被封禁的列表&#xff0c;…

【实践记录】github仓库的更新

首先登录&#xff0c;参考&#xff1a;记一次github连接本地git_如何连接github-CSDN博客 SSH&#xff1a; git config --global user.name "GitHubUsername" git config --global user.email "emailexample.com" ssh-keygen -t ed25519 -C "emailex…

Nature图形复现—Graphpad绘制带P值的含数据点的小提琴图

带 P 值的含数据点的小提琴图是一种科研数据可视化图表&#xff0c;它同时呈现数据的分布特征、原始观测值和统计显著性&#xff1a;通过小提琴形状展示概率密度分布&#xff08;反映数据集中趋势和离散程度&#xff09;&#xff0c;叠加抖动散点显示所有原始数据点&#xff08…

mongodb源代码分析createCollection命令由create.idl变成create_gen.cpp过程

mongodb命令db.createCollection(name, options)创建一个新集合。由于 MongoDB 在命令中首次引用集合时会隐式创建集合&#xff0c;因此此方法主要用于创建使用特定选项的新集合。例如&#xff0c;您使用db.createCollection()创建&#xff1a;固定大小集合&#xff1b;集群化集…

达梦(DM8)常用管理SQL命令(3)

达梦(DM8)常用管理SQL命令(3) 1.表空间 -- 查看表空间信息 SQL> SELECT * FROM v$tablespace;-- 查看数据文件 SQL> SELECT * FROM v$datafile;-- 表空间使用情况 SQL> SELECT df.tablespace_name "表空间名称",df.bytes/1024/1024 "总大小(MB)&q…

【Django】-5- ORM的其他用法

一、&#x1f680; ORM 新增数据魔法&#xff01;核心目标教你用 Django ORM 给数据库 新增数据 &#xff01;就像给数据库 “生小数据宝宝”&#x1f476;方法 1&#xff1a;实例化 Model save&#xff08;一步步喂数据&#xff09;obj Feedback() # 实例化 obj.quality d…

Flink Checkpoint机制:大数据流处理的坚固护盾

引言在大数据技术蓬勃发展的当下&#xff0c;数据处理框架层出不穷&#xff0c;Flink 凭借其卓越的流批一体化处理能力&#xff0c;在大数据流处理领域占据了举足轻重的地位 。它以高吞吐量、低延迟和精准的一次性语义等特性&#xff0c;成为众多企业处理实时数据的首选工具。在…

【STM32-HAL】 SPI通信与Flash数据写入实战

文章目录1.参考教程2. 4种时间模式3. 3个编程接口3.1 HAL_StatusTypeDef HAL_SPI_Transmit(...) &#xff1a;3.1.1 参数说明3.1.2 例子3.2 HAL_StatusTypeDef HAL_SPI_Receive(...) &#xff1a;3.2.1参数说明3.2.2 例子3.3 HAL_StatusTypeDef HAL_SPI_TransmitReceive(...) &…

SNR-Aware Low-light Image Enhancement 论文阅读

信噪比感知的低光照图像增强 摘要 本文提出了一种新的低光照图像增强解决方案&#xff0c;通过联合利用信噪比&#xff08;SNR&#xff09;感知的变换器&#xff08;transformer&#xff09;和卷积模型&#xff0c;以空间变化的操作方式动态增强像素。对于极低信噪比&#xff0…