每日清理

This commit is contained in:
2026-08-20 12:03:17 +08:00
parent 143df60485
commit 22b95db2f9
23 changed files with 614 additions and 581 deletions

View File

@@ -2,101 +2,47 @@ package task
import (
"context"
stderrors "errors"
"fmt"
"time"
"github.com/bytedance/sonic"
"github.com/hibiken/asynq"
"go.uber.org/zap"
"github.com/break/junhong_cmp_fiber/internal/application/auditarchive"
)
// AuditMonthlyRetentionPayload 是人工补跑月度清理时可选的任务载荷
type AuditMonthlyRetentionPayload struct {
ArchiveMonth string `json:"archive_month"`
}
// AuditMonthlyRetentionHandler 处理归档完整性门禁与上月在线日志物理清理。
type AuditMonthlyRetentionHandler struct {
// AuditRetentionHandler 连续校验并按日物理清理已结束的在线日志
type AuditRetentionHandler struct {
service *auditarchive.Service
logger *zap.Logger
cleanupEnabled bool
}
// NewAuditMonthlyRetentionHandler 创建月度日志留存清理处理器。
func NewAuditMonthlyRetentionHandler(service *auditarchive.Service, logger *zap.Logger, cleanupEnabled bool) *AuditMonthlyRetentionHandler {
return &AuditMonthlyRetentionHandler{service: service, logger: logger, cleanupEnabled: cleanupEnabled}
// NewAuditRetentionHandler 创建日留存处理器。
func NewAuditRetentionHandler(service *auditarchive.Service, logger *zap.Logger, cleanupEnabled bool) *AuditRetentionHandler {
return &AuditRetentionHandler{service: service, logger: logger, cleanupEnabled: cleanupEnabled}
}
// Handle 校验整月归档后按固定顺序分批物理删除 PostgreSQL 在线日志
func (h *AuditMonthlyRetentionHandler) Handle(ctx context.Context, task *asynq.Task) error {
if !h.cleanupEnabled {
return h.handleDryRun(ctx, task)
}
// Handle 在关闭清理开关时只读校验,开启后从最早未完成日连续删除
func (h *AuditRetentionHandler) Handle(ctx context.Context, _ *asynq.Task) error {
if h.service == nil {
return fmt.Errorf("月度日志留存清理服务未配置")
return fmt.Errorf("日志留存服务未配置")
}
startedAt := time.Now()
var result auditarchive.RetentionResult
var err error
if len(task.Payload()) == 0 {
result, err = h.service.CleanupPreviousMonth(ctx)
} else {
var payload AuditMonthlyRetentionPayload
if unmarshalErr := sonic.Unmarshal(task.Payload(), &payload); unmarshalErr != nil {
return fmt.Errorf("解析月度日志留存清理任务载荷失败: %w", unmarshalErr)
}
month, parseErr := parseArchiveMonth(payload.ArchiveMonth)
if parseErr != nil {
return parseErr
}
result, err = h.service.CleanupMonth(ctx, month)
}
fields := []zap.Field{
zap.String("archive_month", result.Month), zap.Int64("audit_event_count", result.EventCount),
zap.Int64("event_resource_count", result.ResourceCount), zap.Int64("integration_log_count", result.IntegrationCount),
zap.Duration("duration", time.Since(startedAt)), zap.Int("manifest_count", len(result.ManifestKeys)),
results, err := h.service.RetainPendingDays(ctx, h.cleanupEnabled)
for _, result := range results {
h.logger.Info("日志日留存处理完成",
zap.String("archive_date", result.ArchiveDate), zap.Bool("cleanup_enabled", h.cleanupEnabled),
zap.Int64("audit_event_count", result.EventCount), zap.Int64("event_resource_count", result.ResourceCount),
zap.Int64("integration_log_count", result.IntegrationCount), zap.Duration("duration", result.Duration))
}
if err != nil {
fields = append(fields, zap.String("severity", "critical"), zap.Error(err))
h.logger.Error("月度日志留存清理失败PostgreSQL 整月清理已阻断或等待断点续跑", fields...)
var blocked *auditarchive.RetentionBlockedError
if stderrors.As(err, &blocked) {
h.logger.Error("日志日留存日期推进已阻断", zap.String("archive_date", blocked.ArchiveDate), zap.String("source", blocked.Source), zap.String("failure_category", "archive_or_validation"), zap.Error(err))
} else {
h.logger.Error("日志日留存日期推进已阻断", zap.String("source", "retention"), zap.String("failure_category", "internal"), zap.Error(err))
}
return err
}
h.logger.Info("月度日志留存清理完成", fields...)
return nil
}
func (h *AuditMonthlyRetentionHandler) handleDryRun(ctx context.Context, task *asynq.Task) error {
if h.service == nil {
return fmt.Errorf("月度日志留存演练服务未配置")
}
var result auditarchive.RetentionResult
var err error
if len(task.Payload()) == 0 {
result, err = h.service.ValidatePreviousMonth(ctx)
} else {
var payload AuditMonthlyRetentionPayload
if unmarshalErr := sonic.Unmarshal(task.Payload(), &payload); unmarshalErr != nil {
return fmt.Errorf("解析月度日志留存演练任务载荷失败: %w", unmarshalErr)
}
month, parseErr := parseArchiveMonth(payload.ArchiveMonth)
if parseErr != nil {
return parseErr
}
result, err = h.service.ValidateMonth(ctx, month)
}
fields := []zap.Field{
zap.Bool("cleanup_enabled", false), zap.String("archive_month", result.Month),
zap.Int64("audit_event_count", result.EventCount), zap.Int64("event_resource_count", result.ResourceCount),
zap.Int64("integration_log_count", result.IntegrationCount), zap.Int64("estimated_cleanup_batches", result.EstimatedBatches),
zap.Duration("validation_duration", result.Duration), zap.Int("manifest_count", len(result.ManifestKeys)),
}
if err != nil {
fields = append(fields, zap.String("severity", "critical"), zap.Error(err))
h.logger.Error("审计日志月度只读演练失败,物理清理保持关闭", fields...)
return err
}
h.logger.Info("审计日志月度只读演练通过,物理清理保持关闭", fields...)
return nil
}

View File

@@ -18,12 +18,7 @@ type IntegrationDailyArchivePayload struct {
ArchiveDate string `json:"archive_date"`
}
// IntegrationMonthlyFinalizePayload 是人工月度复核时可选的任务载荷
type IntegrationMonthlyFinalizePayload struct {
ArchiveMonth string `json:"archive_month"`
}
// IntegrationArchiveHandler 处理 Integration Log 每日归档与月度最终复核。
// IntegrationArchiveHandler 处理 Integration Log 每日归档
type IntegrationArchiveHandler struct {
service *auditarchive.Service
logger *zap.Logger
@@ -61,33 +56,6 @@ func (h *IntegrationArchiveHandler) HandleDaily(ctx context.Context, task *asynq
return nil
}
// HandleMonthlyFinalize 执行上一个完整自然月复核,或按任务载荷复核指定月份。
func (h *IntegrationArchiveHandler) HandleMonthlyFinalize(ctx context.Context, task *asynq.Task) error {
if h.service == nil {
return fmt.Errorf("Integration Log 归档服务未配置")
}
var err error
if len(task.Payload()) == 0 {
err = h.service.FinalizePreviousIntegrationMonth(ctx)
} else {
var payload IntegrationMonthlyFinalizePayload
if unmarshalErr := sonic.Unmarshal(task.Payload(), &payload); unmarshalErr != nil {
return fmt.Errorf("解析 Integration Log 月度复核任务载荷失败: %w", unmarshalErr)
}
month, parseErr := parseArchiveMonth(payload.ArchiveMonth)
if parseErr != nil {
return parseErr
}
err = h.service.FinalizeIntegrationMonth(ctx, month)
}
if err != nil {
h.logger.Error("Integration Log 月度最终版本复核失败,后续清理必须阻止", zap.Error(err))
return err
}
h.logger.Info("Integration Log 月度最终版本复核完成")
return nil
}
func parseArchiveDate(value string) (time.Time, error) {
location, err := time.LoadLocation(constants.AuditArchiveTimezone)
if err != nil {
@@ -99,15 +67,3 @@ func parseArchiveDate(value string) (time.Time, error) {
}
return date, nil
}
func parseArchiveMonth(value string) (time.Time, error) {
location, err := time.LoadLocation(constants.AuditArchiveTimezone)
if err != nil {
return time.Time{}, fmt.Errorf("加载 Integration Log 归档时区失败: %w", err)
}
month, err := time.ParseInLocation("2006-01", value, location)
if err != nil {
return time.Time{}, fmt.Errorf("解析 Integration Log 归档月份失败: %w", err)
}
return month, nil
}