package main import ( "context" "fmt" "github.com/afex/hystrix-go/hystrix" consul "github.com/asim/go-micro/plugins/registry/consul/v4" "github.com/dtm-labs/dtm/client/dtmcli" "github.com/go-micro/plugins/v4/wrapper/select/roundrobin" opentracing2 "github.com/go-micro/plugins/v4/wrapper/trace/opentracing" "github.com/lithammer/shortuuid/v3" "github.com/opentracing/opentracing-go" "go-micro.dev/v4/client" "go-micro.dev/v4/web" //"goproduct/common" common "git.mashibing.com/msb_47094/shopping-comm" "goproduct/proto" "log" "net" "net/http" "strconv" "github.com/gin-gonic/gin" "go-micro.dev/v4" "go-micro.dev/v4/registry" ) // 获取远程服务的客户端 func main() { const ( //DTM 服务地址 DtmServer = "http://192.168.100.131:36789/api/dtmsvr" QSBusi = "http://192.168.1.135:6668" //注意 ) var CartId int32 = 1 var Number int32 = 1 resp := &proto.AddCartResp{} router := gin.Default() //注册到consul consulReg := consul.NewRegistry(func(options *registry.Options) { options.Addrs = []string{"192.168.100.131:8500"} }) //初始化链路追踪的jaeper t, io, err := common.NewTracer("shop-cart-client", "192.168.100.131:6831") if err != nil { log.Println(err) } defer io.Close() opentracing.SetGlobalTracer(t) //熔断器 hystrixStreamHandler := hystrix.NewStreamHandler() hystrixStreamHandler.Start() go func() { err := http.ListenAndServe(net.JoinHostPort("192.168.100.1", "9096"), hystrixStreamHandler) if err != nil { log.Panic(err) } }() rpcServer := micro.NewService( //micro.Name("shop-product-client"), micro.Registry(consulReg), //服务发现 micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())), //加入熔断器 micro.WrapClient(NewClientHystrixWrapper()), //负载均衡 micro.WrapClient(roundrobin.NewClientWrapper()), ) AddCartClient := proto.NewAddCartService("shop-cart", rpcServer.Client()) UpdateCartClient := proto.NewUpdateCartService("shop-cart", rpcServer.Client()) ShowProductDetailClient := proto.NewShowProductDetailService("shop-product", rpcServer.Client()) ShowDetailSkuClient := proto.NewShowDetailSkuService("shop-product", rpcServer.Client()) GetUserTokenClient := proto.NewGetUserTokenService("shop-user", rpcServer.Client()) UpdateSkuClient := proto.NewUpdateSkuService("shop-product", rpcServer.Client()) //添加购物车 router.GET("/increase", func(c *gin.Context) { number, _ := strconv.Atoi(c.Request.FormValue("number")) productId, _ := strconv.Atoi(c.Request.FormValue("productId")) productSkuId, _ := strconv.Atoi(c.Request.FormValue("productSkuId")) uuid := c.Request.Header["Uuid"][0] cc := common.GetInput(uuid) out := common.SQ(cc) sum := 0 for o := range out { sum += o } //Token校验 //拼接请求信息 tokenReq := &proto.TokenReq{ Uuid: uuid, } //响应 tokenResp, err := GetUserTokenClient.GetUserToken(context.TODO(), tokenReq) //拼接请求信息 respErr := &proto.AddCartResp{} if err != nil || tokenResp.IsLogin == false { log.Println("GetUserToken err : ", err) common.RespFail(c.Writer, respErr, "未登录!") return } log.Println("GetUserToken success : ", tokenResp) //拼接请求信息 req := &proto.AddCartReq{ Number: int32(number), ProductId: int32(productId), ProductSkuId: int32(productSkuId), UserId: int32(sum), } resp := &proto.AddCartResp{} //商品详情 reqDetail := &proto.ProductDetailReq{ Id: int32(productId), } respDetail, err := ShowProductDetailClient.ShowProductDetail(context.TODO(), reqDetail) if err != nil { log.Println("ShowProductDetail err : ", err) common.RespFail(c.Writer, respErr, "查询商品详情失败!") return } if respDetail != nil { req.ProductName = respDetail.ProductDetail[0].Name req.ProductMainPicture = respDetail.ProductDetail[0].MainPicture } //log.Println(" /ShowProductDetail resp :", respDetail) //SKU详情 reqDetail.Id = req.ProductSkuId respSkuDetail, err := ShowDetailSkuClient.ShowDetailSku(context.TODO(), reqDetail) //log.Println(" /ShowDetailSku resp :", respSkuDetail) //添加购物车 远程调用服务 //log.Println(" /AddCart req :", req) if respSkuDetail.ProductSku[0].Stock < req.Number { common.RespFail(c.Writer, &proto.AddCartResp{}, "库存不足,添加失败") return } sku := respSkuDetail.ProductSku[0] sku.Stock -= req.Number updateSkuReq := &proto.UpdateSkuReq{ ProductSku: sku, } respUpdate, err := UpdateSkuClient.UpdateSku(context.TODO(), updateSkuReq) if err != nil { log.Println(" /UpdateSku err :", err) common.RespFail(c.Writer, resp, "修改库存失败!") return } log.Println(" /UpdateSkuClient resp :", respUpdate.IsSuccess) //开始增加购物车 resp, err = AddCartClient.AddCart(context.TODO(), req) //根据响应做输出 if err != nil { log.Println("addCart err ", err) updateSkuReq.ProductSku.Stock += req.Number _, err = UpdateSkuClient.UpdateSku(context.TODO(), updateSkuReq) log.Println("rollback sku is Err :", err) common.RespFail(c.Writer, resp, "添加购物车失败!") return } resp.ProductSkuSimple = respSkuDetail.ProductSku[0] resp.ProductSimple = respDetail.ProductDetail[0] log.Println(" /AddCart resp :", resp) ////writer data message row total field common.RespOK(c.Writer, resp, "请求成功") }) //开始拆分 DTM服务 // router.POST("/updateSku", func(c *gin.Context) { req := &proto.UpdateSkuReq{} if err := c.BindJSON(req); err != nil { log.Fatalln(err) } _, err := UpdateSkuClient.UpdateSku(context.TODO(), req) if err != nil { log.Println("/updateSku err ", err) c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "修改库存失败!"}) return } c.JSON(http.StatusOK, gin.H{"updateSku": "SUCCESS", "Message": "修改库存成功!"}) }) router.POST("/updateSku-compensate", func(c *gin.Context) { req := &proto.UpdateSkuReq{} if err := c.BindJSON(req); err != nil { log.Fatalln(err) } req.ProductSku.Stock += Number _, err := UpdateSkuClient.UpdateSku(context.TODO(), req) if err != nil { log.Println("/updateSku err ", err) c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "回滚库存失败!"}) return } c.JSON(http.StatusOK, gin.H{"updateSku-compensate": "SUCCESS", "Message": "回滚库存成功!"}) }) router.POST("/addCart", func(c *gin.Context) { req := &proto.AddCartReq{} if err := c.BindJSON(req); err != nil { log.Fatalln(err) } resp, err = AddCartClient.AddCart(context.TODO(), req) CartId = resp.ID //测试异常 //err = errors.New("400", "测试异常", 400) if err != nil { log.Println("/addCart err ", err) c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "新增购物车失败!"}) return } c.JSON(http.StatusOK, gin.H{"addCart": "SUCCESS", "Message": "新增购物车成功!"}) }) router.POST("/addCart-compensate", func(c *gin.Context) { req := &proto.AddCartReq{} if err := c.BindJSON(req); err != nil { log.Fatalln(err) } req.Id = CartId resp, err = UpdateCartClient.UpdateCart(context.TODO(), req) CartId = resp.ID if err != nil { log.Println("/addCart-compensate err ", err) c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "删除购物车失败!"}) return } c.JSON(http.StatusOK, gin.H{"addCart-compensate": "SUCCESS", "Message": "删除购物车成功!"}) }) router.GET("/addShoppingCart", func(c *gin.Context) { number, _ := strconv.Atoi(c.Request.FormValue("number")) productId, _ := strconv.Atoi(c.Request.FormValue("productId")) productSkuId, _ := strconv.Atoi(c.Request.FormValue("productSkuId")) uuid := c.Request.Header["Uuid"][0] cc := common.GetInput(uuid) out := common.SQ(cc) sum := 0 for o := range out { sum += o } //Token校验 //拼接请求信息 tokenReq := &proto.TokenReq{ Uuid: uuid, } //响应 tokenResp, err := GetUserTokenClient.GetUserToken(context.TODO(), tokenReq) //拼接请求信息 respErr := &proto.AddCartResp{} if err != nil || tokenResp.IsLogin == false { log.Println("GetUserToken err : ", err) common.RespFail(c.Writer, respErr, "未登录!") return } log.Println("GetUserToken success : ", tokenResp) //拼接请求信息 req := &proto.AddCartReq{ Number: int32(number), ProductId: int32(productId), ProductSkuId: int32(productSkuId), UserId: int32(sum), } resp := &proto.AddCartResp{} //商品详情 reqDetail := &proto.ProductDetailReq{ Id: int32(productId), } respDetail, err := ShowProductDetailClient.ShowProductDetail(context.TODO(), reqDetail) if err != nil { log.Println("ShowProductDetail err : ", err) common.RespFail(c.Writer, respErr, "查询商品详情失败!") return } if respDetail != nil { req.ProductName = respDetail.ProductDetail[0].Name req.ProductMainPicture = respDetail.ProductDetail[0].MainPicture } //log.Println(" /ShowProductDetail resp :", respDetail) //SKU详情 reqDetail.Id = req.ProductSkuId respSkuDetail, err := ShowDetailSkuClient.ShowDetailSku(context.TODO(), reqDetail) //log.Println(" /ShowDetailSku resp :", respSkuDetail) //添加购物车 远程调用服务 //log.Println(" /AddCart req :", req) if respSkuDetail.ProductSku[0].Stock < req.Number { common.RespFail(c.Writer, &proto.AddCartResp{}, "库存不足,添加失败") return } sku := respSkuDetail.ProductSku[0] sku.Stock -= req.Number Number = req.Number // updateSkuReq := &proto.UpdateSkuReq{ ProductSku: sku, } resp.ProductSkuSimple = respSkuDetail.ProductSku[0] resp.ProductSimple = respDetail.ProductDetail[0] //全局事务 gid := shortuuid.New() saga := dtmcli.NewSaga(DtmServer, gid). Add(QSBusi+"/updateSku", QSBusi+"/updateSku-compensate", updateSkuReq). Add(QSBusi+"/addCart", QSBusi+"/addCart-compensate", req) err = saga.Submit() if err != nil { log.Println("saga submit err :", err) common.RespFail(c.Writer, resp, "添加失败") } log.Println(" /saga submit submit :", gid) ////writer data message row total field common.RespOK(c.Writer, resp, "请求成功") }) service := web.NewService( web.Address(":6668"), web.Name("shop-cart-client"), web.Registry(consulReg), web.Handler(router), ) //启动服务 service.Run() } type clientWrapper struct { client.Client } func (c clientWrapper) Call(ctx context.Context, req client.Request, resp interface{}, opts ...client.CallOption) error { return hystrix.Do(req.Service()+"."+req.Endpoint(), func() error { //正常执行 fmt.Println("call success ", req.Service()+"."+req.Endpoint()) return c.Client.Call(ctx, req, resp, opts...) }, func(err error) error { fmt.Println("call err :", err) return err }) } func NewClientHystrixWrapper() client.Wrapper { return func(i client.Client) client.Client { return &clientWrapper{i} } }