feat(M4): 生命周期 + 审计 — 到期锁定/回收 cron、审计查询/CSV 导出/每日归档、settings 动态策略
This commit is contained in:
+55
-15
@@ -1,28 +1,35 @@
|
||||
// Package cron 提供定时任务:邮件重试、过期扫描、回收、审计归档。
|
||||
// M0 注册任务框架(过期扫描/回收在 M1/M4 接入);M3 接入邮件失败重试;
|
||||
// 单实例部署说明见 PLAN §11。
|
||||
// M0 注册任务框架;M3 接入邮件失败重试;M4 接入生命周期(到期锁定/回收)
|
||||
// 与审计归档;单实例部署说明见 PLAN §11。
|
||||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"ws_usernode/internal/config"
|
||||
"ws_usernode/internal/mail"
|
||||
"ws_usernode/internal/service"
|
||||
)
|
||||
|
||||
// Jobs 聚合定时任务依赖与注册。
|
||||
type Jobs struct {
|
||||
db *gorm.DB
|
||||
mailer mail.Retryable
|
||||
log *slog.Logger
|
||||
cfg *config.Config
|
||||
mailer mail.Retryable
|
||||
lifecycle *service.LifecycleService
|
||||
audit *service.AuditService
|
||||
settings *service.SettingService
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
// New 创建定时任务集合。mailer 为邮件队列(失败重试,PLAN F5)。
|
||||
func New(db *gorm.DB, mailer mail.Retryable, log *slog.Logger) *Jobs {
|
||||
return &Jobs{db: db, mailer: mailer, log: log}
|
||||
// New 创建定时任务集合。
|
||||
// mailer 为邮件队列(失败重试,M3);lifecycle 为账号生命周期(M4);
|
||||
// audit/settings 用于每日审计归档(M4)。
|
||||
func New(cfg *config.Config, mailer mail.Retryable, lifecycle *service.LifecycleService, audit *service.AuditService, settings *service.SettingService, log *slog.Logger) *Jobs {
|
||||
return &Jobs{cfg: cfg, mailer: mailer, lifecycle: lifecycle, audit: audit, settings: settings, log: log}
|
||||
}
|
||||
|
||||
// Register 将任务注册到 cron。
|
||||
@@ -34,10 +41,43 @@ func (j *Jobs) Register(c *cron.Cron) {
|
||||
}
|
||||
})
|
||||
|
||||
// 过期扫描(M4):每日扫描到期账号,锁系统账号 + 邮件通知
|
||||
// 回收任务(M4):超回收期账号自动回收(userdel + 保留审计)
|
||||
// 审计归档(M4):每日将过期审计记录导出归档后清理
|
||||
c.AddFunc("@daily", func() {
|
||||
j.log.Info("cron: daily maintenance tick (tasks to be implemented in M1/M4)")
|
||||
})
|
||||
// 每日维护:过期扫描 → 回收 → 审计归档(M4)
|
||||
c.AddFunc("@daily", j.dailyMaintenance)
|
||||
|
||||
// 到期扫描额外每 6 小时跑一次:避免错过当日到期账号
|
||||
c.AddFunc("@every 6h", j.scanExpired)
|
||||
}
|
||||
|
||||
// dailyMaintenance 每日一次:到期扫描、超期回收、审计归档。
|
||||
func (j *Jobs) dailyMaintenance() {
|
||||
ctx := context.Background()
|
||||
j.scanExpired()
|
||||
if n, err := j.lifecycle.Recycle(ctx); err != nil {
|
||||
j.log.Error("cron: recycle failed", "err", err)
|
||||
} else if n > 0 {
|
||||
j.log.Info("cron: recycled accounts", "count", n)
|
||||
}
|
||||
j.archiveAudit()
|
||||
}
|
||||
|
||||
// scanExpired 到期扫描:锁定系统账号 + 邮件通知。
|
||||
func (j *Jobs) scanExpired() {
|
||||
ctx := context.Background()
|
||||
if n, err := j.lifecycle.ScanExpired(ctx); err != nil {
|
||||
j.log.Error("cron: expire scan failed", "err", err)
|
||||
} else if n > 0 {
|
||||
j.log.Info("cron: expired accounts locked", "count", n)
|
||||
}
|
||||
}
|
||||
|
||||
// archiveAudit 审计归档:将超过保留期的记录归档后清理(archive_dir 未配置时跳过)。
|
||||
func (j *Jobs) archiveAudit() {
|
||||
ctx := context.Background()
|
||||
retention := j.settings.AuditRetention(ctx)
|
||||
before := time.Now().Add(-retention)
|
||||
if n, err := j.audit.Archive(ctx, j.cfg.Audit.ArchiveDir, before); err != nil {
|
||||
j.log.Error("cron: audit archive failed", "err", err)
|
||||
} else if n > 0 {
|
||||
j.log.Info("cron: audit archived", "count", n, "before", before.Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user