Dpz.Core.Web.Jobs
Dpz.Core.Web.Jobs 是 dpz.core 的后台任务宿主,基于 ASP.NET Core、Hangfire、RabbitMQ 和 SignalR,提供周期任务、消息消费、文件传输以及 CI/CD 发布流水线
当前版本与入口
- Target Framework:
.NET 10 - Hangfire Dashboard:
/jobs - 发布流水线页面:
/Pipeline/Index - 文件发送页面:
/transfer或/transfer/send - 文件接收页面:
/transfer/receive/{key?} - 文件传输 Hub:
/transfer/hub - 发布状态 Hub:
/pipeline-notification - 登录入口:
/sign.html - SSO 回调:
/auth/callback - 注销入口:
/logout
当前本地启动配置来自 Properties/launchSettings.json:
https://localhost:7164http://localhost:5078
功能
Hangfire 周期任务
Jobs 使用 MongoDB 作为 Hangfire 存储,存储前缀为 hangfire 周期任务在应用启动时注册;关闭配置开关时会移除对应的 Hangfire 任务
| 任务 | Cron | 实际用途 | 配置开关 |
|---|---|---|---|
删除旧数据 | 1 */5 * * * | 清理 IT 之家过期数据 | hangfireStatus:ItHomeDelete |
爬取数据 | 1 */3 * * * | 抓取 IT 之家 RSS 并发布文章相关消息 | hangfireStatus:ItHomeUpdate |
更新Steam | 0 0 20 ? * ? | 同步 Steam 游戏库及图片 | hangfireStatus:SteamUpdate |
备份 | 0 0 22 ? * ? | 备份 MongoDB 和 AgileConfig 数据 | hangfireStatus:Backup |
云储存空目录清理 | 30 3 * * * | 清理对象存储中的空目录 | hangfireStatus:CosDirCleanup |
同步代码结构 | 0 */6 * * * | 拉取代码并同步代码目录结构到数据库 | 始终注册 |
图片元信息回填 | 17 * * * * | 查询历史候选数据并发布图片元信息采集消息 | 始终注册 |
应用数据备份 | 0 0 21 ? * 4 | 复制程序目录到备份目标目录 | 始终注册 |
消息队列已消费记录清理 | 30 12 * * * | 清理超过 7 天的已消费 Outbox 记录 | 始终注册 |
Cron 表达式由 Hangfire 使用,涉及 UTC 的任务以代码注释和服务器时区为准,备份类任务、对象存储清理和历史记录清理包含任务级防重或并发控制
RabbitMQ 消息消费者
应用通过 AddMessageConsumer<TMessage, THandler>() 显式注册以下消费者:
| 消息 | 处理器 | 用途 |
|---|---|---|
DeleteMarkdownMessage | DeleteMarkdownHandler | 删除 Markdown 关联数据 |
RemoveImagesMessage | RemoveImagesHandler | 移除图片关联数据 |
AddCommentCountMessage | AddCommentCountHandler | 更新评论计数 |
AddDanmakuCountMessage | AddDanmakuCountHandler | 更新弹幕计数 |
AnalyzeCodeMessage | AnalyzeCodeHandler | 执行代码内容分析并写回结果 |
SendMasterEmailMessage | SendMasterEmailHandler | 发送站点通知邮件 |
SendReplyEmailMessage | SendReplyEmailHandler | 发送评论回复邮件 |
SendEmailVerifyCodeMessage | SendEmailVerifyCodeHandler | 发送邮箱验证码 |
GetImageMetadataMessage | GetImageMetadataHandler | 获取图片元信息并触发后续回写 |
同时注册 Outbox 重试后台服务,保证消息投递失败后可以继续补发
文件传输
文件传输使用需要登录的 SignalR Hub,房间状态保存在应用内存中:
- 发送方访问
/transfer/send并创建房间 - 系统生成房间 Key 和接收链接
- 接收方访问
/transfer/receive/{key}加入房间 - 双方通过
/transfer/hub协商文件、暂停/恢复、取消和完成状态 - 文件以 Base64 分片传输,并使用分片确认进行流控
- 任意一方断开连接时,关联房间会被清理并通知另一方
房间存储和会话服务为单例,过期房间由 FileTransferRoomCleanupService 清理
CI/CD 发布流水线
发布流水线页面为 /Pipeline/Index,需要登录并拥有 Permissions.System 权限 相关接口和实时推送同样受权限保护
页面支持:
- 选择
Dpz.Core、Dpz.WebApi、Dpz.Core.Auth中的一个或多个项目 - 自动从构建机的
.csproj读取版本号 - 手动指定统一版本 Tag,例如
1.2.3 - 查看拉取代码、构建镜像和部署发布三个阶段的实时输出
- 按构建机、部署服务器和项目切换日志面板
- 当线上版本与即将发布版本一致时,等待 2 分钟二次确认
- 查看最近的 CI/CD 历史记录和单次执行的只读步骤日志
一次发布的实际流程为:
- 校验配置中心
ssh节点 - 使用 SSH 连接构建机并执行
git pull - 自动读取目标项目版本,或使用用户指定的 Tag
- 通过
Pipeline:VersionHosts请求各服务的/api/version,检查同版本发布 - 在构建机执行 Docker build,并推送版本 Tag 和
latestTag - 并行连接配置的部署服务器,拉取版本镜像并重建容器
- 在 MongoDB 中保存本次执行的历史快照
开发环境会跳过真实的镜像构建、推送和部署,仅模拟流水线阶段,同一时间只允许一个发布运行,实时日志通过 /pipeline-notification 推送
配置
必需的通用配置
配置由本地 JSON 和 AgileConfig 合并提供,敏感字段不要写入公开文档或提交到仓库
{
"AgileConfig": {
"appId": "Dpz.Core.Web.Jobs",
"secret": "your-secret",
"nodes": "https://your-agile-config-server",
"env": "DEV"
},
"ConnectionStrings": {
"mongodb": "mongodb://localhost:27017/dpz",
"hangfireMongodb": "mongodb://localhost:27017/dpz-hangfire"
},
"RabbitMQ": {
"HostName": "localhost",
"Port": 5672,
"UserName": "guest",
"Password": "guest",
"VirtualHost": "/"
}
}
hangfireMongodb 专用于 Hangfire 存储,不能用文档中的示例凭据替代生产配置
周期任务开关
{
"hangfireStatus": {
"ItHomeDelete": false,
"ItHomeUpdate": false,
"SteamUpdate": false,
"Backup": false,
"CosDirCleanup": false
}
}
未配置或值为 false 时,以上五个可选任务不会运行,TaskListHandle 虽然可能出现在旧的开发配置中,但当前 Jobs 注册代码不读取它
程序与数据库备份
程序目录备份和数据库备份都使用 BackupRootPath 作为目标根目录:
{
"BackupRootPath": "/mnt/backup",
"BackupSettings": {
"BackupProgramPath": "/home/ubuntu/program",
"IgnorePaths": [],
"IgnoreFiles": ["LOCK"],
"IgnoreExtensions": []
}
}
数据库备份保存到 BackupRootPath/db/{year}/{month},程序目录备份保存到,BackupRootPath/program/{year}/{month}/backup_{yyyyMMdd},同一天已有目录时会追加 _1、_2 等后缀,不覆盖旧备份
忽略规则:
IgnorePaths:必须位于程序备份根目录下,匹配目录及其子目录IgnoreFiles:按文件 basename 精确匹配,匹配区分大小写且为全局规则IgnoreExtensions:按FileInfo.Extension精确匹配,匹配区分大小写IgnoreExtensions为[]时不启用扩展名过滤
CI/CD SSH 配置
发布流水线读取配置中心或配置文件中的 ssh 节点:
{
"ssh": {
"Build": {
"Host": "build.example.com",
"Port": 22,
"Username": "deploy",
"Password": "your-password",
"Workspace": "/home/deploy/dpz.core"
},
"Registry": "registry.example.com",
"Servers": {
"SERVER_1": {
"Host": "app.example.com",
"Port": 22,
"Username": "deploy",
"Password": "your-password",
"Project": 6
}
}
},
"Pipeline": {
"VersionHosts": {
"DpzCore": "https://core.example.com",
"DpzWebApi": "https://api.example.com",
"DpzCoreAuth": "https://auth.example.com"
}
}
}
ssh.Build 负责拉取源码、读取版本和构建镜像,ssh.Servers 决定各服务器部署哪些项目,Registry 用于配置校验和部署拓扑说明。
当前内置构建命令使用本机构建机上的 127.0.0.1:3383 镜像仓库构建并推送,部署命令从 registry.dpangzi.com 拉取版本镜像;如需改用其他仓库,应同步修改Hangfire/Build/BuiltInCommands.cs。
版本探测
流水线会对 Pipeline:VersionHosts 中已配置的地址请求 /api/version 探测失败或未配置的项目会跳过同版本检查,不会单独阻断发布 如果线上版本和本次发布版本相同,用户必须在页面中确认,否则 2 分钟后本次发布中止
认证与跨域
- 使用 OpenIddict Client 接入统一认证中心
- 登录成功后以 Cookie 保存
VmUserInfo - Data Protection 密钥持久化到 MongoDB,支持多实例共享
- Dashboard、Pipeline、文件传输页面和 Hub 均要求登录
- Dashboard 和 Pipeline 额外要求
Permissions.System - CORS 来源读取
Origins配置,并允许 Credentials
项目结构
Dpz.Core.Web.Jobs/
├── Controllers/
│ ├── HomeController.cs # 首页、登录回调
│ ├── FileTransferController.cs # 文件发送和接收页面
│ └── PipelineController.cs # 发布、状态、确认和历史接口
├── Hangfire/
│ ├── HangfireConfiguration.cs # Hangfire Dashboard 和周期任务注册
│ ├── BuildActivator.cs # CI/CD 构建、推送、部署和历史记录
│ ├── Build/ # SSH 配置、版本探测和构建命令
│ ├── BackupActivator.cs # MongoDB 和 AgileConfig 备份
│ ├── BackupProgramActivator.cs # 程序目录备份
│ ├── CosDirectoryCleanupActivator.cs
│ ├── ImageMetadataBackfillActivator.cs
│ ├── ItHomeActivator.cs
│ ├── MessageOutboxCleanupActivator.cs
│ ├── SteamActivator.cs
│ └── SyncCodeActivator.cs
├── Hubs/
│ ├── FileTransferHub.cs # 文件分片传输
│ └── PipelineHub.cs # 发布日志和阶段推送
├── MessageHandlers/ # RabbitMQ 消息消费者
├── Models/FileTransfer/ # 文件传输状态和结果模型
├── Security/ # OpenIddict、Cookie 和权限校验
├── Services/
│ ├── TaskService.cs # 任务公共处理逻辑
│ └── FileTransfer/ # 房间、会话和过期清理
├── Views/ # Razor 页面
├── wwwroot/
│ ├── scripts/file-transfer/ # 文件传输前端
│ ├── scripts/pipeline/ # 发布流水线前端
│ └── styles/ # 页面样式
├── RegisterDependencyInjectionExtensions.cs
└── Program.cs
本地开发
启动
cd src
dotnet run --project .\Dpz.Core.Web.Jobs\Dpz.Core.Web.Jobs.csproj
构建
cd src
dotnet build .\Dpz.Core.Web.Jobs\Dpz.Core.Web.Jobs.csproj
部署
正式环境使用 systemd 运行 Jobs,不使用 Docker 容器运行该项目
发布命令:
cd src/Dpz.Core.Web.Jobs
dotnet publish .\Dpz.Core.Web.Jobs.csproj `
--configuration Release `
--output ..\publish\job
systemd 服务示例:
[Unit]
Description=Dpz.Core.Web.Jobs
After=network.target
[Service]
WorkingDirectory=/home/ubuntu/program
ExecStart=/usr/bin/dotnet /home/ubuntu/program/Dpz.Core.Web.Jobs.dll
Restart=always
RestartSec=10
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_RSS_NET_GC_MEMORY=true
[Install]
WantedBy=multi-user.target
修改服务文件后执行:
sudo systemctl daemon-reload
sudo systemctl enable dpz-job.service
sudo systemctl restart dpz-job.service
sudo systemctl status dpz-job.service
Jobs 依赖外部 MongoDB、Redis、RabbitMQ、AgileConfig、对象存储和认证中心 正式部署后应重点检查服务状态、Hangfire /jobs、RabbitMQ 消费日志、备份目录以及 Pipeline 页面配置校验结果