2025-09-13 20:00:27 +08:00
|
|
|
|
package kills
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-09-14 17:01:36 +08:00
|
|
|
|
"context"
|
2025-09-13 20:00:27 +08:00
|
|
|
|
"encoding/base64"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
"log"
|
|
|
|
|
|
"math/rand"
|
2025-09-14 21:12:37 +08:00
|
|
|
|
"net/http"
|
2025-09-13 20:00:27 +08:00
|
|
|
|
"time"
|
2025-09-14 17:01:36 +08:00
|
|
|
|
"toutoukan/init/redisInit"
|
2025-09-14 21:12:37 +08:00
|
|
|
|
"toutoukan/model/usermodel/userOrder"
|
|
|
|
|
|
"toutoukan/rocketmq/killmq/mqproducer"
|
2025-09-14 17:01:36 +08:00
|
|
|
|
"toutoukan/utill/scripts"
|
2025-09-13 20:00:27 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func GenerateOrderID() string {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
timestamp := time.Now().Format("20060102150405")
|
2025-09-13 20:00:27 +08:00
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
randomBytes := make([]byte, 8)
|
2025-09-13 20:00:27 +08:00
|
|
|
|
_, err := rand.Read(randomBytes)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Sprintf("ORD%s%011d", timestamp, time.Now().UnixNano()%100000000000)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 17:01:36 +08:00
|
|
|
|
randomStr := base64.URLEncoding.EncodeToString(randomBytes)[:11]
|
2025-09-13 20:00:27 +08:00
|
|
|
|
return fmt.Sprintf("ORD%s%s", timestamp, randomStr)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func Userkill(c *gin.Context) {
|
2025-09-14 21:12:37 +08:00
|
|
|
|
var req userOrder.UserRequest
|
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误", "detail": err.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
fmt.Printf("用户%d请求购买%s", req.UserID, req.Order)
|
|
|
|
|
|
|
|
|
|
|
|
OrderID := GenerateOrderID()
|
2025-09-13 20:00:27 +08:00
|
|
|
|
|
2025-09-14 21:12:37 +08:00
|
|
|
|
// 1. Redis扣减库存(不变)
|
|
|
|
|
|
result, err := redisInit.RedisClient.Eval(context.Background(), scripts.Luascript_forkill, []string{req.Order, "mayiming"}, 1, OrderID).Int()
|
2025-09-14 17:01:36 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Printf("Redis 脚本执行错误: %v", err)
|
|
|
|
|
|
c.JSON(500, gin.H{"error": "库存操作失败", "detail": err.Error()})
|
2025-09-13 20:00:27 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-09-14 21:12:37 +08:00
|
|
|
|
if result != 1 {
|
2025-09-14 17:01:36 +08:00
|
|
|
|
c.JSON(200, gin.H{"result": "库存不足,扣减失败"})
|
2025-09-14 21:12:37 +08:00
|
|
|
|
return
|
2025-09-13 20:00:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-14 21:12:37 +08:00
|
|
|
|
// 2. 发送MQ消息(关键:发送失败需回滚Redis)
|
|
|
|
|
|
msgSent := false
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
// 若消息未发送成功,回滚Redis库存
|
|
|
|
|
|
if !msgSent {
|
|
|
|
|
|
log.Printf("消息发送失败,回滚Redis库存,商品: %s,用户: %d", req.Order, req.UserID)
|
|
|
|
|
|
// 回滚Redis:库存+1,同时移除可能的订单记录(根据Lua脚本逻辑调整)
|
|
|
|
|
|
redisInit.RedisClient.Incr(context.Background(), req.Order)
|
|
|
|
|
|
// 若Lua脚本中记录了订单ID(如存到set中),也需删除
|
|
|
|
|
|
//redisInit.RedisClient.SRem(context.Background(), req.Order, OrderID)
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
2025-09-14 17:01:36 +08:00
|
|
|
|
|
2025-09-14 21:12:37 +08:00
|
|
|
|
// 发送消息(同步发送,确保拿到发送结果)
|
|
|
|
|
|
sendErr := mqproducer.SendNormalMessage(OrderID, req.Order, req.UserID)
|
|
|
|
|
|
if sendErr != nil {
|
|
|
|
|
|
log.Printf("MQ消息发送失败: %v", sendErr)
|
|
|
|
|
|
c.JSON(500, gin.H{"error": "消息发送失败", "detail": sendErr.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 消息发送成功,标记为已发送(避免defer回滚)
|
|
|
|
|
|
msgSent = true
|
|
|
|
|
|
c.JSON(200, gin.H{"result": "库存扣减成功"})
|
|
|
|
|
|
}
|