Commit 3a6792ae by hcy

并发问题

parent 32b298ac
......@@ -3,10 +3,13 @@ package controller
import (
"context"
"encoding/json"
"fmt"
"github.com/tidwall/gjson"
"go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/logger"
"go_sku_server/pkg/mongo"
"go_sku_server/service"
"gopkg.in/mgo.v2/bson"
"sync"
"time"
......@@ -41,14 +44,11 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
// 1. 提前提取所有请求参数(在主协程中,避免在子协程中访问 gin.Context)
requestParams := service.ExtractRequestParams(ctx)
// 2. 创建带超时的 context,用于控制所有协程的生命周期
// 5秒超时后,所有子协程都会收到取消信号
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() // 确保函数返回时取消所有协程,释放资源
//抽取自营 或者联营 goods_id
zyService := service.ZiyingService{} //实例化自营查询
lyService := service.LyService{} //实例化联营查询
SpuService := service.SpuService{}
var goodsIdArr []string
if GoodsIdStr == "" {
goodsIdMap := ctx.PostFormMap("goods_id")
......@@ -63,11 +63,64 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
return nil
}
//////////初始化公共变量 以及 批量查询///////////
zyGoodsId := make([]string, 0, goodsSliceCount)
lyGoodsId := make([]string, 0, goodsSliceCount)
for _, goodsId := range goodsIdArr {
if len(goodsId) < 19 { //自营
zyGoodsId = append(zyGoodsId, goodsId)
} else { //联营
lyGoodsId = append(lyGoodsId, goodsId)
}
}
//批量查询redis-sku信息
redisLySkuArr := gredis.Hmget("default_r", "sku", lyGoodsId)
//批量查询归档的sku
preSkuIds := make([]int64, 0)
for _, goodsId := range goodsIdArr {
if redisLySkuArr[goodsId] == "" {
preSkuIds = append(preSkuIds, gconv.Int64(goodsId))
}
}
if len(preSkuIds) > 0 {
var prevSkuArr []bson.M
prevSkuMongo := mongo.Conn("pre_sku")
query := bson.M{
"sku_id": bson.M{
"$in": preSkuIds,
},
}
err := prevSkuMongo.DB("ichunt").C("prev_sku").Find(query).All(&prevSkuArr)
if err != nil {
fmt.Println("查询失败: %v", err)
}
for _, preSkuOne := range prevSkuArr {
jsonBytes, err := json.Marshal(preSkuOne)
if err != nil {
continue
}
preSkuOneStr := string(jsonBytes)
skuId := gjson.Get(preSkuOneStr, "sku_id").String()
redisLySkuArr[skuId] = preSkuOneStr
}
}
//查询spu信息
redisLySpuArr := SpuService.GetSpuList(redisLySkuArr)
SpuService.SetInit() //设置查询公共变量
/////////////////多线程///////////////////////////
var wg sync.WaitGroup
ch := make(chan sync.Map, 50) //管道
wgMax := 3 //线程数量最多多少
wgcount := 0 //当前线程数
zyGoodsId := make([]string, 0, goodsSliceCount)
lyGoodsId := make([]string, 0, goodsSliceCount)
temp := make(map[string]interface{}) //最后输出计算结果
for _, goodsId := range goodsIdArr {
//if len(goodsIdArr) > 100 {
// common.Output(ctx, 1001, "查询型号ID不得超过100个", "")
......@@ -90,87 +143,49 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
zyService.ZyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
}(ctx, requestParams, idsToProcess, ch)
zyGoodsId = zyGoodsId[:0]
}
} else { //联营
lyGoodsId = append(lyGoodsId, goodsId)
if len(lyGoodsId) >= goodsSliceCount {
common.PrintDebugHtml(ctx, "ly增加协程1002:")
common.PrintDebugHtml(ctx, lyGoodsId)
wg.Add(1)
idsToProcess := make([]string, len(lyGoodsId))
copy(idsToProcess, lyGoodsId)
common.PrintDebugHtml(ctx, "ly增加协程:"+goodsId)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
lyService.LyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
lyGoodsId = lyGoodsId[:0]
//单个sku详情
if _, ok := redisLySkuArr[goodsId]; !ok {
temp[goodsId] = false
continue
}
skuStr := redisLySkuArr[goodsId]
spuId := gjson.Get(skuStr, "spu_id").String()
if _, ok := redisLySpuArr[spuId]; !ok {
temp[goodsId] = false
continue
}
}
}
if len(zyGoodsId) > 0 {
common.PrintDebugHtml(ctx, "zy增加协程1003:")
common.PrintDebugHtml(ctx, zyGoodsId)
wg.Add(1) //协程计数一
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, skuStr, goodsId, spuStr string, ch chan sync.Map) {
defer wg.Done()
lyService.LyGoodsDetail(ctx, params, skuStr, goodsId, spuStr, ch)
}(ctx, requestParams, skuStr, goodsId, redisLySpuArr[spuId], ch)
idsToProcess := make([]string, len(zyGoodsId))
copy(idsToProcess, zyGoodsId)
wg.Add(1)
wgcount += 1
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
zyService.ZyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
if wgcount >= wgMax {
println("线程数量:" + gconv.String(wgcount))
wg.Wait() // 等待所有登记的goroutine都结束
wgcount = 0
}
}
}
if len(lyGoodsId) > 0 {
common.PrintDebugHtml(ctx, "ly增加协程1004:")
common.PrintDebugHtml(ctx, lyGoodsId)
wg.Add(1)
idsToProcess := make([]string, len(lyGoodsId))
copy(idsToProcess, lyGoodsId)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
lyService.LyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
if wgcount > 0 {
//println("等待结束,现有运行线程数:" + gconv.String(wgcount))
//wg.Wait()
}
// 开启一个协程,等待所有任务完成,然后关闭channel
// 使用 context 来控制这个等待协程的生命周期
go func() {
// 创建一个 done channel 用于通知 wg.Wait() 完成
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
// 等待 wg.Wait() 完成或 context 取消
select {
case <-done:
// 所有协程都正常完成
close(ch)
case <-ctxWithTimeout.Done():
// context 超时,不再等待剩余协程
// 等待一小段时间让协程有机会退出
time.Sleep(300 * time.Millisecond)
close(ch)
logger.Log("等待协程完成超时,强制关闭channel", "sku", 1)
}
}()
close(ch)
//异步map最后转成map
temp := make(map[string]interface{})
for {
select {
case GoodsRes, ok := <-ch:
......@@ -182,36 +197,12 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
temp[s] = v
return true
})
case <-ctxWithTimeout.Done():
// context 超时或被取消
logger.Log("协程整体处理超时,所有子协程已收到取消信号", "sku", 1)
// 继续从 channel 读取已经发送的数据,避免协程阻塞
// 等待 channel 被关闭(由上面的 wg.Wait() 协程关闭)
cleanupTimeout := time.After(500 * time.Millisecond)
for {
select {
case GoodsRes, ok := <-ch:
if !ok {
// channel 已关闭,所有协程都已退出
logger.Log("channel已关闭,返回结果", "sku", 1)
return temp
}
// 收集已经发送的数据
GoodsRes.Range(func(k, v interface{}) bool {
s, _ := k.(string)
temp[s] = v
return true
})
case <-cleanupTimeout:
// 清理超时,强制返回
logger.Log("清理超时,强制返回", "sku", 1)
return temp
}
}
case <-time.After(20 * time.Second):
println("协程超时20秒")
return temp
}
}
}
func Synchronization(ctx *gin.Context) {
......
......@@ -7,5 +7,5 @@ type PrevSku struct {
ID bson.ObjectId `bson:"_id"`
SkuId int64 `bson:"sku_id"`
SpuId int64 `bson:"spu_id"`
SupplierId int64 `bson:"supplier_id"`
SupplierId int32 `bson:"supplier_id"`
}
......@@ -9,7 +9,6 @@ import (
"go_sku_server/pkg/mongo"
"go_sku_server/service/sorter"
"sort"
"strconv"
"sync"
"gopkg.in/mgo.v2"
......@@ -37,14 +36,7 @@ type Power struct {
联营数据详情
使用 context.Context 控制协程生命周期,避免 gin.Context 在协程中的并发问题
*/
func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, goodsIds []string, ch chan sync.Map) {
// 检查 context 是否已取消(超时或主动取消)
select {
case <-ctx.Done():
logger.Log("LyGoodsDetail: context已取消,直接返回", "sku", 1)
return
default:
}
func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, skuStr, goodsId, spuStr string, ch chan sync.Map) {
redisConn := gredis.Conn("search_r")
redisConnSpu := gredis.Conn("spu")
......@@ -68,270 +60,219 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//是否展示spu额外信息
showSpuExtra := params.ShowSpuExtra
//批量获取商品详情
skuArr := gredis.Hmget("default_r", "sku", goodsIds)
//为了性能着想,这边也先去批量获取spu的信息
var spuService SpuService
spuList := spuService.getSpuList(skuArr)
GoodsRes := sync.Map{}
for goodsId, skuStr := range skuArr {
// 在处理每个商品前检查 context 是否已取消
select {
case <-ctx.Done():
logger.Log("LyGoodsDetail: 处理过程中context被取消", "sku", 1)
// 不发送不完整的数据,直接返回让协程尽快退出
return
default:
}
//初始化有序map,拼接data数据,就是从redis取出初始数据
sku := model.InitSkuData(skuStr)
var spu string
if skuStr == "" {
// 如果redis中找不到sku数据,尝试从prev_sku MongoDB中查找
skuId, err := strconv.ParseInt(goodsId, 10, 64)
if err != nil {
GoodsRes.Store(goodsId, false)
continue
}
var prevSku model.PrevSku
err = prevSkuMongo.DB("ichunt").C("prev_sku").Find(bson.M{"sku_id": skuId}).One(&prevSku)
if err != nil {
// 如果在prev_sku中也找不到,则保持默认值
GoodsRes.Store(goodsId, false)
continue
}
//初始化有序map,拼接data数据,就是从redis取出初始数据
sku := model.InitSkuData(skuStr)
spu := spuStr
// 根据找到的spu_id去spu的redis中查找
spuIdStr := strconv.FormatInt(prevSku.SpuId, 10)
spuStr, _ := redis.String(redisConnSpu.Do("HGET", "spu", spuIdStr))
if spuStr == "" {
// 如果spu缓存也没有,保持默认值
GoodsRes.Store(goodsId, false)
continue
}
sku.SupplierId = prevSku.SupplierId
sku.SpuId = spuIdStr
spu = spuStr
} else {
spu = spuList[sku.SpuId]
}
sku.GoodsId = goodsId
//读取包装字段的缓存(分别是DGK,avnet,mro)
if sku.SupplierId == 7 || sku.SupplierId == 13 || sku.SupplierId == 1688 || sku.SupplierId == 17 {
//sku_raw_map哪里写入(成意写的)
packing, _ := redis.String(redisConnSpu.Do("HGET", "sku_raw_map", goodsId))
sku.Packing = gjson.Get(packing, "pack").String()
}
sku = ls.GetGoodsImages(sku, spu)
sku = ls.GetPdf(sku, spu)
//用spuInfo补全信息
sku = ls.CombineSup(sku, spu)
// 2023.11.20 DGK商品的包装若为“Tape & Reel (TR)”,则递增量=起订量
if sku.SupplierId == 7 && sku.Packing == "Tape & Reel (TR)" {
sku.Multiple = sku.Moq
}
//获取商品名称
//spuName和GoodsName不是一个东西,不能公用,因为订单系统也用到了goods_name这个字段
//而下单的时候,只能给spu型号才行
if sku.GoodsName != "" {
sku.GoodsName = gjson.Get(spu, "spu_name").String()
}
if sku.GoodsName == "" {
sku.GoodsName = gjson.Get(spu, "spu_name").String()
}
sku.GoodsId = goodsId
//读取包装字段的缓存(分别是DGK,avnet,mro)
if sku.SupplierId == 7 || sku.SupplierId == 13 || sku.SupplierId == 1688 || sku.SupplierId == 17 {
//sku_raw_map哪里写入(成意写的)
packing, _ := redis.String(redisConnSpu.Do("HGET", "sku_raw_map", goodsId))
sku.Packing = gjson.Get(packing, "pack").String()
}
sku = ls.GetGoodsImages(sku, spu)
sku = ls.GetPdf(sku, spu)
//用spuInfo补全信息
sku = ls.CombineSup(sku, spu)
// 2023.11.20 DGK商品的包装若为“Tape & Reel (TR)”,则递增量=起订量
if sku.SupplierId == 7 && sku.Packing == "Tape & Reel (TR)" {
sku.Multiple = sku.Moq
//获取品牌名称
brandId := gjson.Get(spu, "brand_id").Int()
brandName, _ := redis.String(redisConn.Do("HGET", "brand", brandId))
sku.BrandName = brandName
sku.BrandId = brandId
//判断是否要取精简信息
if fast != "1" {
sku = ls.GetGoodsClass(sku, spu)
//仅提供价格和库存
if sku.GoodsName != "" && brandId != 0 {
sku.ErpTax = ls.GetErpTax(sku.GoodsName, brandName)
}
//获取商品名称
//spuName和GoodsName不是一个东西,不能公用,因为订单系统也用到了goods_name这个字段
//而下单的时候,只能给spu型号才行
if sku.GoodsName != "" {
sku.GoodsName = gjson.Get(spu, "spu_name").String()
sku.SupplierName = ls.GetPoolSupplierName(sku.SupplierId)
if showAttr == "1" {
//获取属性
sku.Attrs = ls.GetSpuAttr(sku.SpuId)
}
if sku.GoodsName == "" {
sku.GoodsName = gjson.Get(spu, "spu_name").String()
if sku.Attrs == nil {
sku.Attrs = []interface{}{}
}
}
//获取品牌名称
brandId := gjson.Get(spu, "brand_id").Int()
brandName, _ := redis.String(redisConn.Do("HGET", "brand", brandId))
sku.BrandName = brandName
sku.BrandId = brandId
//判断是否要取精简信息
if fast != "1" {
sku = ls.GetGoodsClass(sku, spu)
//仅提供价格和库存
if sku.GoodsName != "" && brandId != 0 {
sku.ErpTax = ls.GetErpTax(sku.GoodsName, brandName)
}
sku.SupplierName = ls.GetPoolSupplierName(sku.SupplierId)
if showAttr == "1" {
//获取属性
sku.Attrs = ls.GetSpuAttr(sku.SpuId)
}
if sku.Attrs == nil {
sku.Attrs = []interface{}{}
}
//获取在途库存信息
if showStockInfo == "1" && sku.OldGoodsId != 0 {
sku.StockInfo = ls.getStockInfo(sku.SupplierId, sku.OldGoodsId)
}
//格式化为对象返回
if sku.StockInfo == nil {
type StockInfoResult struct {
}
sku.StockInfo = new(StockInfoResult)
}
//获取在途库存信息
if showStockInfo == "1" && sku.OldGoodsId != 0 {
sku.StockInfo = ls.getStockInfo(sku.SupplierId, sku.OldGoodsId)
}
//格式化为对象返回
if sku.StockInfo == nil {
type StockInfoResult struct {
}
sku.StockInfo = new(StockInfoResult)
}
//判断是否需要返回sku详情
if showSkuDetail == "1" {
sku.SkuDetail = ls.GetSkuDetail(sku.GoodsId)
}
//判断是否需要返回sku详情
if showSkuDetail == "1" {
sku.SkuDetail = ls.GetSkuDetail(sku.GoodsId)
}
//是否需要返回spu额外信息
if showSpuExtra == "1" {
sku.SpuExtra = ls.GetSpuExtra(sku.SpuId)
}
//是否需要返回spu额外信息
if showSpuExtra == "1" {
sku.SpuExtra = ls.GetSpuExtra(sku.SpuId)
}
brandPack := gjson.Get(spu, "brand_pack").String()
if brandPack != "" {
sku.SpuExtra.BrandPack = brandPack
sku.BrandPack = brandPack
}
brandPack := gjson.Get(spu, "brand_pack").String()
if brandPack != "" {
sku.SpuExtra.BrandPack = brandPack
sku.BrandPack = brandPack
}
//获取供应链标准品牌
//什么是供应链的标准品牌 供应链那边报关的时候要求他们的标准品牌,所以要吧自己的品牌映射上去
//继来那边对接的标准品牌(下单的时候)
sku.ScmBrand = ls.GetScmBrand(brandId)
//获取供应链标准品牌
//什么是供应链的标准品牌 供应链那边报关的时候要求他们的标准品牌,所以要吧自己的品牌映射上去
//继来那边对接的标准品牌(下单的时候)
sku.ScmBrand = ls.GetScmBrand(brandId)
//获取新版的标准品牌
sku.StandardBrand = ls.GetStandardBrand(brandId)
//获取新版的标准品牌
sku.StandardBrand = ls.GetStandardBrand(brandId)
//处理过期, 2022.7.13 专卖没有过期
if sku.SupplierId != 17 && gjson.Get(skuStr, "is_expire").Int() != 0 {
sku.LadderPrice = nil
}
//处理过期, 2022.7.13 专卖没有过期
if sku.SupplierId != 17 && gjson.Get(skuStr, "is_expire").Int() != 0 {
sku.LadderPrice = nil
//处理活动
sku.AcType = 0
sku.AllowCoupon = 1
//这里获取活动价格和活动类型(折扣打折活动)
sku = ls.GetActivity(sku)
priceService := PriceService{}
//这里又有一个判断,如果是非猎芯的,目前只有爱智,通过org_id来判断
//1是猎芯,3是爱智
switch sku.OrgId {
//case为0是为了兼容价格体系之前的价格
case 0:
case 1:
//这里猎芯和寄售都是走同一套的价格体系了
//获取系数和价格
sku = ls.GetCoefficientAndPrice(sku)
//获取自定义价格后的阶梯价
customPriceService := CustomPrice{}
sku.CustomPriceList, _ = customPriceService.getCustomPriceList(sku)
sku = priceService.GetActivityPrice(sku)
case 3:
//如果是寄售的,不走价格体系
if sku.Source == 12 {
break
}
//处理活动
sku.AcType = 0
sku.AllowCoupon = 1
//这里获取活动价格和活动类型(折扣打折活动)
sku = ls.GetActivity(sku)
priceService := PriceService{}
//这里又有一个判断,如果是非猎芯的,目前只有爱智,通过org_id来判断
//1是猎芯,3是爱智
switch sku.OrgId {
//case为0是为了兼容价格体系之前的价格
case 0:
case 1:
//这里猎芯和寄售都是走同一套的价格体系了
//这里还有个特殊判断,要兼容华云改价格体系之前的老数据
//判断组织是3并且阶梯价数量为2,并且第一个阶梯不是0的就是老数据
//兼容最近的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2)
//又要兼容新的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2) + 销售限价(阶梯数量3)
//还有一种特殊情况,那就是只上传成本价和销售限价,那么就是要走价格体系的(最新)
if (sku.OrgId == 3 && len(sku.LadderPrice) == 2 && sku.LadderPrice[0].Purchases != 0) ||
(sku.OrgId == 3 && len(sku.LadderPrice) == 3 && sku.LadderPrice[0].Purchases == 0) ||
(sku.OrgId == 3 && len(sku.LadderPrice) == 4 && sku.LadderPrice[0].Purchases == 0) {
sku.LadderPrice = priceService.GetIEdgePrice(sku.LadderPrice)
} else {
//判断是不是华云的,如果是的话,还要判断是不是有成本价和销售限价,如果是的话,要把销售限价去掉,因为走的价格体系的前提是有成本价的时候
//只能有一个阶梯,并且阶梯数量为0
if sku.OrgId == 3 && len(sku.LadderPrice) == 2 {
sku.LadderPrice = sku.LadderPrice[:1]
}
//这里猎芯和华云都是走同一套的价格体系了
//获取系数和价格
sku = ls.GetCoefficientAndPrice(sku)
//获取自定义价格后的阶梯价
customPriceService := CustomPrice{}
sku.CustomPriceList, _ = customPriceService.getCustomPriceList(sku)
sku = priceService.GetActivityPrice(sku)
case 3:
//如果是寄售的,不走价格体系
if sku.Source == 12 {
break
}
//这里还有个特殊判断,要兼容华云改价格体系之前的老数据
//判断组织是3并且阶梯价数量为2,并且第一个阶梯不是0的就是老数据
//兼容最近的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2)
//又要兼容新的价格配置,即上传了成本价(阶梯数量0) + 会员价(阶梯数量1) + 企业价(阶梯数量2) + 销售限价(阶梯数量3)
//还有一种特殊情况,那就是只上传成本价和销售限价,那么就是要走价格体系的(最新)
if (sku.OrgId == 3 && len(sku.LadderPrice) == 2 && sku.LadderPrice[0].Purchases != 0) ||
(sku.OrgId == 3 && len(sku.LadderPrice) == 3 && sku.LadderPrice[0].Purchases == 0) ||
(sku.OrgId == 3 && len(sku.LadderPrice) == 4 && sku.LadderPrice[0].Purchases == 0) {
sku.LadderPrice = priceService.GetIEdgePrice(sku.LadderPrice)
} else {
//判断是不是华云的,如果是的话,还要判断是不是有成本价和销售限价,如果是的话,要把销售限价去掉,因为走的价格体系的前提是有成本价的时候
//只能有一个阶梯,并且阶梯数量为0
if sku.OrgId == 3 && len(sku.LadderPrice) == 2 {
sku.LadderPrice = sku.LadderPrice[:1]
}
//这里猎芯和华云都是走同一套的价格体系了
//获取系数和价格
sku = ls.GetCoefficientAndPrice(sku)
//获取自定义价格后的阶梯价
customPriceService := CustomPrice{}
sku.CustomPriceList, _ = customPriceService.getCustomPriceList(sku)
//这里还要针对华云的阶梯价进行一次转换,因为要兼容目前华云的使用方式
if sku.OrgId == 3 {
sku.LadderPrice = customPriceService.transformIEdgeLadderPrice(sku)
}
//这里还要针对华云的阶梯价进行一次转换,因为要兼容目前华云的使用方式
if sku.OrgId == 3 {
sku.LadderPrice = customPriceService.transformIEdgeLadderPrice(sku)
}
sku = priceService.GetActivityPrice(sku)
}
sku = priceService.GetActivityPrice(sku)
}
//仅提供价格和库存
if fast != "1" {
if sku.SupplierId != 0 {
sku.SuppExtendFee = ls.GetExtendFee(sku.SupplierId, sku.Canal)
}
//还要处理货期
delivery := ls.GetDelivery(sku.SupplierId, sku.Canal)
if sku.CnDeliveryTime == "" {
sku.CnDeliveryTime = delivery["cn_delivery"]
}
if sku.HkDeliveryTime == "" {
sku.HkDeliveryTime = delivery["hk_delivery"]
}
//只要是寄售的,大陆交期都是0.5工作日
if sku.Source == 12 {
sku.CnDeliveryTime = "0.5工作日"
}
//仅提供价格和库存
if fast != "1" {
if sku.SupplierId != 0 {
sku.SuppExtendFee = ls.GetExtendFee(sku.SupplierId, sku.Canal)
}
//最小起订量要大于阶梯价的最小阶梯数量
if len(sku.LadderPrice) > 0 {
//排序
sort.Sort(sorter.LadderPriceSorter(sku.LadderPrice))
//取出第一个阶梯价
purchases := sku.LadderPrice[0].Purchases
if purchases > sku.Moq {
sku.Moq = purchases
}
//还要处理货期
delivery := ls.GetDelivery(sku.SupplierId, sku.Canal)
if sku.CnDeliveryTime == "" {
sku.CnDeliveryTime = delivery["cn_delivery"]
}
//处理是否可以购买
if sku.Mpq == 0 {
sku.Mpq = 1
if sku.HkDeliveryTime == "" {
sku.HkDeliveryTime = delivery["hk_delivery"]
}
if len(sku.LadderPrice) > 0 {
sku.LadderPriceResult = sku.LadderPrice
} else {
sku.LadderPriceResult = []int{}
//只要是寄售的,大陆交期都是0.5工作日
if sku.Source == 12 {
sku.CnDeliveryTime = "0.5工作日"
}
//判断是否可以购买
sku.IsBuy = ls.GetIsBuy(sku)
if sku.IsBuy == 0 && sku.OrgId != 1 {
sku.AcType = 0
}
//最小起订量要大于阶梯价的最小阶梯数量
if len(sku.LadderPrice) > 0 {
//排序
sort.Sort(sorter.LadderPriceSorter(sku.LadderPrice))
//取出第一个阶梯价
purchases := sku.LadderPrice[0].Purchases
if purchases > sku.Moq {
sku.Moq = purchases
}
}
sku.Stock = ls.GetStock(sku)
//处理是否可以购买
if sku.Mpq == 0 {
sku.Mpq = 1
}
//获取标签信息
var TagService TagsService
sku.GoodsTag = TagService.GetLyTags(sku)
if len(sku.LadderPrice) > 0 {
sku.LadderPriceResult = sku.LadderPrice
} else {
sku.LadderPriceResult = []int{}
}
//获取关税以及价格转换
sku = ls.GetTariffAndPrice(sku)
//判断是否可以购买
sku.IsBuy = ls.GetIsBuy(sku)
if sku.IsBuy == 0 && sku.OrgId != 1 {
sku.AcType = 0
}
//最后一步,将sku的全部信息放到有序map里面
GoodsRes.Store(goodsId, sku)
//(*goodsRes)[goodsId] = A
sku.Stock = ls.GetStock(sku)
}
// 发送结果时也要检查 context,避免在超时后阻塞
select {
case <-ctx.Done():
logger.Log("LyGoodsDetail: 发送结果前context已取消,直接返回", "sku", 1)
return
case ch <- GoodsRes:
// 成功发送
}
//获取标签信息
var TagService TagsService
sku.GoodsTag = TagService.GetLyTags(sku)
//获取关税以及价格转换
sku = ls.GetTariffAndPrice(sku)
//最后一步,将sku的全部信息放到有序map里面
GoodsRes.Store(goodsId, sku)
//(*goodsRes)[goodsId] = A
//退出通道
ch <- GoodsRes
}
// 获取活动
......
......@@ -83,9 +83,9 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
//抽取自营 或者联营 goods_id
zyService := ZiyingService{} //实例化自营查询
lyService := LyService{} //实例化联营查询
ch := make(chan sync.Map) //管道
p := 0 //总共协程
//lyService := LyService{} //实例化联营查询
ch := make(chan sync.Map) //管道
p := 0 //总共协程
zyGoodsId := make([]string, 0)
lyGoodsId := make([]string, 0)
for _, goodsId := range goodsIds {
......@@ -102,7 +102,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
} else { //联营
lyGoodsId = append(lyGoodsId, goodsId)
if len(lyGoodsId) >= 10 {
go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
//go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
lyGoodsId = lyGoodsId[:0:0]
p++
}
......@@ -113,7 +113,7 @@ func (ss *SampleService) GetGoods(ctx *gin.Context, goodsIds []string) map[strin
p++
}
if len(lyGoodsId) > 0 {
go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
//go lyService.LyGoodsDetail(ctxWithTimeout, params, lyGoodsId, ch)
p++
}
//异步map最后转成map
......
package service
import (
"github.com/gomodule/redigo/redis"
"github.com/tidwall/gjson"
"go_sku_server/pkg/gredis"
)
type SpuService struct {
var UsdRate float64 //美金匯率
type SpuService struct {
}
func (ss *SpuService) getSpuList(skuArr map[string]string) (spuList map[string]string) {
func (ss *SpuService) GetSpuList(skuArr map[string]string) (spuList map[string]string) {
var spuIds []string
for _, skuStr := range skuArr {
spuId := gjson.Get(skuStr, "spu_id").String()
......@@ -19,3 +21,10 @@ func (ss *SpuService) getSpuList(skuArr map[string]string) (spuList map[string]s
spuList = gredis.Hmget("spu", "spu", spuIds)
return
}
// 设置查询公共变量
func (ss *SpuService) SetInit() {
redisCon := gredis.Conn("default_r")
usdRatio, _ := redis.Float64(redisCon.Do("HGET", "erp_rate", 2))
UsdRate = usdRatio
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment