当前位置: 首页 > news >正文

Hangfire定时部署(.NET 8 + SQL Server)

一、创建 .NET 8 项目

首先创建一个 .NET 8 项目(ASP.NET Core Web 应用或控制台应用),这里以 ASP.NET Core Web API 为例。

二、安装必要的 NuGet 包

核心包(适用于 ASP.NET Core)
Install-Package Hangfire.AspNetCore存储后端(选择一个)
Install-Package Hangfire.SqlServer      # SQL Server
Install-Package Hangfire.Redis.StackExchange  # Redis
Install-Package Hangfire.PostgreSql    # PostgreSQL其他拓展
Install-Package Microsoft.Data.SqlClient
Install-Package Swashbuckle.AspNetCore

三、完整配置步骤(.NET 8 + SQL Server)

  1. 配置连接字符串
    在 appsettings.json 中添加数据库连接:
    需先创建一个数据库
Windows本机连接
{"ConnectionStrings": {"HangfireConnection": "Server=localhost;Database=HangfireNet8;Integrated Security=True;TrustServerCertificate=True"}
}IP账号密码连接"ConnectionStrings": {"HangfireConnection": "Server=127.0.0.1;Database=HangfireDB;User Id=sa;Password=123456;TrustServerCertificate=True;Encrypt=False"}
  1. 配置 Program.cs
using Hangfire;
using Hangfire.Dashboard;
using Hangfire.SqlServer;
using Microsoft.Extensions.Logging;
using System.Net;var builder = WebApplication.CreateBuilder(args);// 添加 Hangfire 服务
builder.Services.AddHangfire(configuration => configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings()// 配置 SQL Server 存储.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection"), new SqlServerStorageOptions{CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),QueuePollInterval = TimeSpan.Zero,UseRecommendedIsolationLevel = true,DisableGlobalLocks = true,EnableHeavyMigrations = true})
);// 添加 Hangfire 服务器
builder.Services.AddHangfireServer(options =>
{options.WorkerCount = Math.Max(Environment.ProcessorCount * 5, 10);options.Queues = new[] { "high", "medium", "low" };options.ShutdownTimeout = TimeSpan.FromMinutes(1);
});// 添加控制器和Swagger服务
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();// 注册应用服务
builder.Services.AddScoped<ITaskService, TaskService>();var app = builder.Build();
var isDevelopment = app.Environment.IsDevelopment();// 配置HTTP请求管道
if (isDevelopment)
{app.UseSwagger();app.UseSwaggerUI();
}app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();// 启用 Hangfire 仪表板
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{Authorization = new[] { new HangfireAuthFilter(isDevelopment) }
});// 定义任务
using (var scope = app.Services.CreateScope())
{var services = scope.ServiceProvider;try{var taskService = services.GetRequiredService<ITaskService>();// 1. 即时任务BackgroundJob.Enqueue(() => taskService.ProcessData("initial"));// 2. 延迟任务(30分钟后执行)BackgroundJob.Schedule(() => taskService.SendNotification("delayed"),TimeSpan.FromMinutes(1));// 3. 循环任务(每小时执行一次)RecurringJob.AddOrUpdate("hourly-cleanup",() => taskService.CleanupResources(),Cron.Hourly,TimeZoneInfo.Local);// 4. 延续任务var parentJobId = BackgroundJob.Enqueue(() => taskService.ProcessOrder(1001));BackgroundJob.ContinueWith(parentJobId,() => taskService.CompleteOrder(1001));}catch (Exception ex){var logger = services.GetRequiredService<ILogger<Program>>();logger.LogError(ex, "注册Hangfire任务时发生错误");}
}app.MapControllers();app.Run();// 自定义授权过滤器 - 修复空值问题
public class HangfireAuthFilter : IDashboardAuthorizationFilter
{private readonly bool _isDevelopment;public HangfireAuthFilter(bool isDevelopment){_isDevelopment = isDevelopment;}public bool Authorize(DashboardContext context){// 确保上下文不为空if (context == null)return false;// 获取HTTP上下文并检查var httpContext = context.GetHttpContext();if (httpContext == null)return false;// 开发环境直接允许访问if (_isDevelopment)return true;// 生产环境检查是否为本地访问var localIpAddress = httpContext.Connection.LocalIpAddress;if (localIpAddress == null)return false;// 明确检查是否为回环地址(IPv4和IPv6)return IPAddress.IsLoopback(localIpAddress);}
}// 任务服务接口
public interface ITaskService
{void ProcessData(string data);void SendNotification(string message);void CleanupResources();void ProcessOrder(int orderId);void CompleteOrder(int orderId);
}// 任务服务实现
public class TaskService : ITaskService
{private readonly ILogger<TaskService> _logger;// 确保日志服务不为空public TaskService(ILogger<TaskService> logger){_logger = logger ?? throw new ArgumentNullException(nameof(logger));}public void ProcessData(string data){if (string.IsNullOrEmpty(data))throw new ArgumentException("数据不能为空", nameof(data));_logger.LogInformation("处理数据: {Data}", data);}public void SendNotification(string message){if (string.IsNullOrEmpty(message))throw new ArgumentException("消息不能为空", nameof(message));_logger.LogInformation("发送通知: {Message}", message);}public void CleanupResources(){_logger.LogInformation("清理资源于 {Time}", DateTime.Now);}public void ProcessOrder(int orderId){if (orderId <= 0)throw new ArgumentOutOfRangeException(nameof(orderId), "订单ID必须大于0");_logger.LogInformation("处理订单: {OrderId}", orderId);}public void CompleteOrder(int orderId){if (orderId <= 0)throw new ArgumentOutOfRangeException(nameof(orderId), "订单ID必须大于0");_logger.LogInformation("订单完成: {OrderId}", orderId);}
}

四、数据库初始化

首次运行应用时,Hangfire 会自动在指定的数据库中创建所需的表结构(约 15 张表),无需手动创建。

五、访问 Hangfire 仪表板

启动应用后,访问 https://localhost:端口/hangfire 即可打开管理界面,在这里可以:
查看所有任务的执行状态
手动触发、暂停或删除循环任务
重试失败的任务
监控服务器状态和性能
在这里插入图片描述

http://www.dtcms.com/a/340886.html

相关文章:

  • Android 资源替换:静态替换 vs 动态替换
  • PHP特有的安全漏洞及渗透测试利用方法(通俗易懂)
  • 项目1总结其一
  • 49 C++ STL模板库18-类模板-pair
  • ROS 2系统Callback Group概念笔记
  • 突发!DeepSeek刚刚开源V3.1-Base
  • UTF-8 编解码可视化分析
  • 【Day 30】Linux-SQL语句
  • C/C++ 与嵌入式岗位常见笔试题详解
  • MYSQL为什么会发生死锁,怎么解决
  • 第三阶段数据-3:数据库脚本生成,备份与还原,分离与附加
  • configtx通道配置文件
  • RHCA08内存管理
  • 对称加密算法
  • 数据库DML语言(增、删、改)
  • 闪电赋能全链路:领码SPARK一体化创新平台
  • 基于HTTP3的WebTransport实践
  • 基于 Java 和 MySQL 的精品课程网站
  • 在完全没有无线网络(Wi-Fi)和移动网络(蜂窝数据)的环境下,使用安卓平板,通过USB数据线(而不是Wi-Fi)来控制电脑(版本2)
  • Ubuntu 重连usb设备(断电和不断电方案)亲测可行
  • 亚马逊新品爆单策略:从传统困境到智能突破
  • LeetCode热题100--101. 对称二叉树--简单
  • C++ 力扣 438.找到字符串中所有字母异位词 题解 优选算法 滑动窗口 每日一题
  • 《数据之舞》
  • GitHub宕机生存指南:从应急协作到高可用架构设计
  • QT-图像灰度处理时QImage.setPixel方法存在的坑
  • 在QT中动态生成控件造成界面卡顿时的鼠标处理
  • Qt设置软件使用期限【新版防修改系统时间】
  • 一个 WPF 文档和工具窗口布局容器
  • GitHub宕机应急指南:无缝协作方案