fix: retry critical writes and allow super login
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
"quyun/v2/providers/storage"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgconn"
|
||||
"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)
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user