fix: retry critical writes and allow super login

This commit is contained in:
2026-01-08 17:37:42 +08:00
parent 8ac82aaeb0
commit 3c159a2e0f
4 changed files with 233 additions and 156 deletions

View File

@@ -62,6 +62,9 @@ func (m *Middlewares) Auth(ctx fiber.Ctx) error {
} }
func (m *Middlewares) SuperAuth(ctx fiber.Ctx) error { func (m *Middlewares) SuperAuth(ctx fiber.Ctx) error {
if isSuperPublicRoute(ctx) {
return ctx.Next()
}
authHeader := ctx.Get("Authorization") authHeader := ctx.Get("Authorization")
if authHeader == "" { if authHeader == "" {
return errorx.ErrUnauthorized.WithMsg("Missing token") return errorx.ErrUnauthorized.WithMsg("Missing token")
@@ -130,3 +133,14 @@ func isPublicRoute(ctx fiber.Ctx) bool {
return false return false
} }
func isSuperPublicRoute(ctx fiber.Ctx) bool {
path := ctx.Path()
method := ctx.Method()
if method == fiber.MethodPost && path == "/super/v1/auth/login" {
return true
}
return false
}

View File

@@ -5,6 +5,7 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"io" "io"
"mime/multipart" "mime/multipart"
"os" "os"
@@ -24,6 +25,7 @@ import (
"quyun/v2/providers/storage" "quyun/v2/providers/storage"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgconn"
"go.ipao.vip/gen/types" "go.ipao.vip/gen/types"
) )
@@ -453,3 +455,57 @@ func (s *common) GetAssetURL(objectKey string) string {
url, _ := s.storage.SignURL("GET", objectKey, 1*time.Hour) url, _ := s.storage.SignURL("GET", objectKey, 1*time.Hour)
return url return url
} }
func retryCriticalWrite(ctx context.Context, fn func() error) error {
backoffs := []time.Duration{
50 * time.Millisecond,
120 * time.Millisecond,
250 * time.Millisecond,
}
var lastErr error
for attempt := 0; attempt <= len(backoffs); attempt++ {
if err := fn(); err != nil {
if !shouldRetryWrite(err) {
return err
}
lastErr = err
if attempt >= len(backoffs) {
return err
}
// 事务冲突/死锁等短暂错误,等待后重试。
if ctx != nil {
select {
case <-ctx.Done():
return errorx.ErrServiceTimeout.WithCause(ctx.Err())
case <-time.After(backoffs[attempt]):
}
} else {
time.Sleep(backoffs[attempt])
}
continue
}
return nil
}
return lastErr
}
func shouldRetryWrite(err error) bool {
var appErr *errorx.AppError
if errors.As(err, &appErr) {
return false
}
return isTransientDBError(err)
}
func isTransientDBError(err error) bool {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) {
switch pgErr.Code {
case "40001", "40P01":
return true
}
}
return false
}

View File

@@ -665,6 +665,8 @@ func (s *creator) ProcessRefund(ctx context.Context, userID, id int64, form *cre
} }
if form.Action == "accept" { if form.Action == "accept" {
// 关键退款事务:遇到数据库冲突/死锁时短暂退避重试,避免退款卡住。
return retryCriticalWrite(ctx, func() error {
return models.Q.Transaction(func(tx *models.Query) error { return models.Q.Transaction(func(tx *models.Query) error {
// 1. Deduct Creator Balance // 1. Deduct Creator Balance
// We credited Creator User Balance in Order.Pay. Now deduct it. // We credited Creator User Balance in Order.Pay. Now deduct it.
@@ -730,6 +732,7 @@ func (s *creator) ProcessRefund(ctx context.Context, userID, id int64, form *cre
return nil return nil
}) })
})
} }
return errorx.ErrBadRequest.WithMsg("无效的操作") return errorx.ErrBadRequest.WithMsg("无效的操作")

View File

@@ -247,7 +247,10 @@ func (s *order) payWithBalance(ctx context.Context, o *models.Order) (*transacti
func (s *order) settleOrder(ctx context.Context, o *models.Order, method, externalID string) error { func (s *order) settleOrder(ctx context.Context, o *models.Order, method, externalID string) error {
var tenantOwnerID int64 var tenantOwnerID int64
err := models.Q.Transaction(func(tx *models.Query) error { // 关键结算事务:遇到数据库冲突/死锁时短暂退避重试,避免支付状态卡死。
err := retryCriticalWrite(ctx, func() error {
tenantOwnerID = 0
return models.Q.Transaction(func(tx *models.Query) error {
// 1. Handle Balance Updates // 1. Handle Balance Updates
if o.Type == consts.OrderTypeRecharge { if o.Type == consts.OrderTypeRecharge {
// Income: Recharge (Credit User Balance) // Income: Recharge (Credit User Balance)
@@ -348,6 +351,7 @@ func (s *order) settleOrder(ctx context.Context, o *models.Order, method, extern
return nil return nil
}) })
})
if err != nil { if err != nil {
return err return err
} }