Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展 Confidence: medium Scope-risk: broad Directive: 后续修改需保持审计事件与业务事务边界一致 Tested: git diff --cached --check Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
63 lines
1.9 KiB
Go
63 lines
1.9 KiB
Go
package audit
|
|
|
|
import (
|
|
"context"
|
|
stderrors "errors"
|
|
"strconv"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/break/junhong_cmp_fiber/pkg/auditcontext"
|
|
"github.com/break/junhong_cmp_fiber/pkg/auditfailure"
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
pkgerrors "github.com/break/junhong_cmp_fiber/pkg/errors"
|
|
)
|
|
|
|
// RecordFailure 在业务回滚后使用独立短事务记录失败或拒绝事实。
|
|
func (w *Writer) RecordFailure(ctx context.Context, db *gorm.DB, input AppendInput, originalErr error) {
|
|
fillFailureInput(&input, originalErr)
|
|
if w == nil || db == nil {
|
|
recordFailureWriteError(ctx, input, pkgerrors.New(pkgerrors.CodeInvalidStatus, "统一审计失败记录接缝未配置"))
|
|
return
|
|
}
|
|
if err := db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
return w.Append(ctx, tx, input)
|
|
}); err != nil {
|
|
recordFailureWriteError(ctx, input, err)
|
|
}
|
|
}
|
|
|
|
func fillFailureInput(input *AppendInput, originalErr error) {
|
|
var appErr *pkgerrors.AppError
|
|
if stderrors.As(originalErr, &appErr) && appErr != nil {
|
|
if input.Result == "" {
|
|
input.Result = constants.AuditResultDenied
|
|
if appErr.Code == pkgerrors.CodeDatabaseError || appErr.Code == pkgerrors.CodeInternalError {
|
|
input.Result = constants.AuditResultFailed
|
|
}
|
|
}
|
|
input.ErrorCode = strconv.Itoa(appErr.Code)
|
|
input.ErrorSummary = appErr.Message
|
|
return
|
|
}
|
|
if input.Result == "" {
|
|
input.Result = constants.AuditResultFailed
|
|
}
|
|
input.ErrorCode = strconv.Itoa(pkgerrors.CodeInternalError)
|
|
input.ErrorSummary = "业务操作失败"
|
|
}
|
|
|
|
func recordFailureWriteError(ctx context.Context, input AppendInput, err error) {
|
|
linkage := auditcontext.From(ctx)
|
|
resourceKey := ""
|
|
for _, resource := range input.Resources {
|
|
if resource.Relation == constants.AuditResourceRelationPrimary {
|
|
resourceKey = resource.Key
|
|
break
|
|
}
|
|
}
|
|
auditfailure.RecordSecondaryWriteFailure(
|
|
input.ActionCode, resourceKey, linkage.RequestID, linkage.CorrelationID, input.ErrorCode, err,
|
|
)
|
|
}
|