diff --git a/controller/user.go b/controller/user.go index a7d59f17..c9795c0c 100644 --- a/controller/user.go +++ b/controller/user.go @@ -844,18 +844,64 @@ type topUpRequest struct { Key string `json:"key"` } -var topUpLock = sync.Mutex{} +var topUpLocks sync.Map +var topUpCreateLock sync.Mutex + +type topUpTryLock struct { + ch chan struct{} +} + +func newTopUpTryLock() *topUpTryLock { + return &topUpTryLock{ch: make(chan struct{}, 1)} +} + +func (l *topUpTryLock) TryLock() bool { + select { + case l.ch <- struct{}{}: + return true + default: + return false + } +} + +func (l *topUpTryLock) Unlock() { + select { + case <-l.ch: + default: + } +} + +func getTopUpLock(userID int) *topUpTryLock { + if v, ok := topUpLocks.Load(userID); ok { + return v.(*topUpTryLock) + } + topUpCreateLock.Lock() + defer topUpCreateLock.Unlock() + if v, ok := topUpLocks.Load(userID); ok { + return v.(*topUpTryLock) + } + l := newTopUpTryLock() + topUpLocks.Store(userID, l) + return l +} func TopUp(c *gin.Context) { - topUpLock.Lock() - defer topUpLock.Unlock() + id := c.GetInt("id") + lock := getTopUpLock(id) + if !lock.TryLock() { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": "充值处理中,请稍后重试", + }) + return + } + defer lock.Unlock() req := topUpRequest{} err := c.ShouldBindJSON(&req) if err != nil { common.ApiError(c, err) return } - id := c.GetInt("id") quota, err := model.Redeem(req.Key, id) if err != nil { common.ApiError(c, err) @@ -866,7 +912,6 @@ func TopUp(c *gin.Context) { "message": "", "data": quota, }) - return } type UpdateUserSettingRequest struct {