收口审计治理与套餐任务进展

Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展
Confidence: medium
Scope-risk: broad
Directive: 后续修改需保持审计事件与业务事务边界一致
Tested: git diff --cached --check
Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
This commit is contained in:
2026-08-05 14:30:54 +08:00
parent b3499adfca
commit 5e552d99bc
178 changed files with 16797 additions and 5674 deletions

View File

@@ -0,0 +1,39 @@
package order_package_invalidate
import (
"context"
"strconv"
"gorm.io/gorm"
"github.com/break/junhong_cmp_fiber/internal/infrastructure/audit"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
)
func (s *Service) writeInvalidateTaskAudit(ctx context.Context, tx *gorm.DB, task *model.OrderPackageInvalidateTask, before, after map[string]any, result, phase, errorCode, errorSummary string) error {
return s.auditWriter.WriteTask(ctx, tx, audit.TaskInput{
EventID: audit.TaskEventID(constants.AuditResourceOrderPackageInvalidateTask, task.ID, phase),
ActionCode: constants.AuditActionOrderPackageInvalidateTaskCreated,
Summary: "创建订单套餐批量失效任务", TaskID: task.ID, TaskNo: task.TaskNo,
Actor: audit.ActorInput{
Kind: constants.AuditActorAccount, ID: strconv.FormatUint(uint64(middleware.GetUserIDFromContext(ctx)), 10),
Name: middleware.GetUsernameFromContext(ctx),
},
Source: constants.AuditSourceAdminAPI, ScopeType: constants.AuditScopePlatform,
Result: result, ErrorCode: errorCode, ErrorSummary: errorSummary,
IdentitySnapshot: map[string]any{"id": task.ID, "task_no": task.TaskNo, "file_name": task.FileName},
BeforeData: before, AfterData: after,
})
}
func invalidateTaskState(task *model.OrderPackageInvalidateTask) map[string]any {
if task == nil {
return nil
}
return map[string]any{
"status": task.Status, "total_count": task.TotalCount,
"success_count": task.SuccessCount, "fail_count": task.FailCount,
}
}

View File

@@ -3,14 +3,18 @@ package order_package_invalidate
import (
"context"
"path/filepath"
"strconv"
"time"
"github.com/hibiken/asynq"
"gorm.io/gorm"
"github.com/break/junhong_cmp_fiber/internal/infrastructure/audit"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/internal/store"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/auditfailure"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
@@ -21,17 +25,23 @@ import (
type Service struct {
taskStore *postgres.OrderPackageInvalidateTaskStore
queueClient *queue.Client
auditWriter *audit.Writer
}
// New 创建 Service 实例
func New(
taskStore *postgres.OrderPackageInvalidateTaskStore,
queueClient *queue.Client,
auditWriters ...*audit.Writer,
) *Service {
return &Service{
service := &Service{
taskStore: taskStore,
queueClient: queueClient,
}
if len(auditWriters) > 0 {
service.auditWriter = auditWriters[0]
}
return service
}
// InvalidateTaskPayload Worker 任务载荷
@@ -59,7 +69,15 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateOrderPackageInvalid
Updater: userID,
}
if err := s.taskStore.Create(ctx, task); err != nil {
if s.auditWriter == nil {
return nil, errors.New(errors.CodeInvalidStatus, "订单套餐失效任务统一审计接缝未配置")
}
if err := s.taskStore.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := s.taskStore.WithTx(tx).Create(ctx, task); err != nil {
return err
}
return s.writeInvalidateTaskAudit(ctx, tx, task, nil, invalidateTaskState(task), constants.AuditResultSuccess, "created", "", "")
}); err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "创建任务失败")
}
@@ -71,7 +89,17 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateOrderPackageInvalid
asynq.Queue(constants.QueueForTaskType(constants.TaskTypeOrderPackageInvalidate)),
)
if err != nil {
s.taskStore.UpdateStatus(ctx, task.ID, model.ImportTaskStatusFailed, "任务入队失败: "+err.Error())
secondaryErr := s.taskStore.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
before := invalidateTaskState(task)
if updateErr := s.taskStore.WithTx(tx).UpdateStatus(ctx, task.ID, model.ImportTaskStatusFailed, "任务入队失败"); updateErr != nil {
return updateErr
}
task.Status, task.ErrorMessage = model.ImportTaskStatusFailed, "任务入队失败"
return s.writeInvalidateTaskAudit(ctx, tx, task, before, invalidateTaskState(task), constants.AuditResultFailed, "enqueue_failed", strconv.Itoa(errors.CodeTaskQueueError), "订单套餐失效任务入队失败")
})
if secondaryErr != nil {
auditfailure.RecordSecondaryWriteFailure(constants.AuditActionOrderPackageInvalidateTaskCreated, task.TaskNo, "", task.TaskNo, strconv.Itoa(errors.CodeTaskQueueError), secondaryErr)
}
}
return s.toResponse(task), nil