folder-controller
folder
folder
folder
folder-class
folder
folder-secure
folder-controller
folder-views
folder-public
docker
csharp
readme

Dpz.Core.Web.Jobs

Dpz.Core.Web.Jobsdpz.core 的后台任务宿主,基于 ASP.NET Core、Hangfire、RabbitMQ 和 SignalR,提供周期任务、消息消费、文件传输以及 CI/CD 发布流水线

生产入口https://task.dpangzi.com

当前版本与入口

  • 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:7164
  • http://localhost:5078

功能

Hangfire 周期任务

Jobs 使用 MongoDB 作为 Hangfire 存储,存储前缀为 hangfire 周期任务在应用启动时注册;关闭配置开关时会移除对应的 Hangfire 任务

任务Cron实际用途配置开关
删除旧数据1 */5 * * *清理 IT 之家过期数据hangfireStatus:ItHomeDelete
爬取数据1 */3 * * *抓取 IT 之家 RSS 并发布文章相关消息hangfireStatus:ItHomeUpdate
更新Steam0 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>() 显式注册以下消费者:

消息处理器用途
DeleteMarkdownMessageDeleteMarkdownHandler删除 Markdown 关联数据
RemoveImagesMessageRemoveImagesHandler移除图片关联数据
AddCommentCountMessageAddCommentCountHandler更新评论计数
AddDanmakuCountMessageAddDanmakuCountHandler更新弹幕计数
AnalyzeCodeMessageAnalyzeCodeHandler执行代码内容分析并写回结果
SendMasterEmailMessageSendMasterEmailHandler发送站点通知邮件
SendReplyEmailMessageSendReplyEmailHandler发送评论回复邮件
SendEmailVerifyCodeMessageSendEmailVerifyCodeHandler发送邮箱验证码
GetImageMetadataMessageGetImageMetadataHandler获取图片元信息并触发后续回写

同时注册 Outbox 重试后台服务,保证消息投递失败后可以继续补发

文件传输

文件传输使用需要登录的 SignalR Hub,房间状态保存在应用内存中:

  1. 发送方访问 /transfer/send 并创建房间
  2. 系统生成房间 Key 和接收链接
  3. 接收方访问 /transfer/receive/{key} 加入房间
  4. 双方通过 /transfer/hub 协商文件、暂停/恢复、取消和完成状态
  5. 文件以 Base64 分片传输,并使用分片确认进行流控
  6. 任意一方断开连接时,关联房间会被清理并通知另一方

房间存储和会话服务为单例,过期房间由 FileTransferRoomCleanupService 清理

CI/CD 发布流水线

发布流水线页面为 /Pipeline/Index,需要登录并拥有 Permissions.System 权限 相关接口和实时推送同样受权限保护

页面支持:

  • 选择 Dpz.CoreDpz.WebApiDpz.Core.Auth 中的一个或多个项目
  • 自动从构建机的 .csproj 读取版本号
  • 手动指定统一版本 Tag,例如 1.2.3
  • 查看拉取代码、构建镜像和部署发布三个阶段的实时输出
  • 按构建机、部署服务器和项目切换日志面板
  • 当线上版本与即将发布版本一致时,等待 2 分钟二次确认
  • 查看最近的 CI/CD 历史记录和单次执行的只读步骤日志

一次发布的实际流程为:

  1. 校验配置中心 ssh 节点
  2. 使用 SSH 连接构建机并执行 git pull
  3. 自动读取目标项目版本,或使用用户指定的 Tag
  4. 通过 Pipeline:VersionHosts 请求各服务的 /api/version,检查同版本发布
  5. 在构建机执行 Docker build,并推送版本 Tag 和 latest Tag
  6. 并行连接配置的部署服务器,拉取版本镜像并重建容器
  7. 在 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 页面配置校验结果

相关项目

评论加载中...