From 6e9db4213052f0c569612e5faa3196f0c7580ba0 Mon Sep 17 00:00:00 2001 From: huangjiajun <582604932@qq.com> Date: Fri, 9 Dec 2022 17:28:37 +0800 Subject: [PATCH] test --- db/db_day_luck_draw_order_jackpot.go | 15 -- db/db_day_luck_draw_period.go | 3 +- db/db_day_luck_draw_period_reward.go | 6 +- db/db_day_luck_draw_setting.go | 19 ++ db/db_day_luck_draw_settle_order.go | 38 +++ db/db_user.go | 9 + db/model/day_luck_draw_order_jackpot.go | 3 - db/model/day_luck_draw_period.go | 1 + db/model/day_luck_draw_settle_order.go | 16 ++ db/model/fin_user_flow.go | 29 +++ db/model/user_profile.go | 91 +++++++ go.mod | 1 + md/app_redis_key.go | 20 ++ md/day_luck_draw_setting.go | 1 + md/fin_user_flow.go | 45 ++++ svc/svc_day_luck_draw_order_jackpot.go | 13 +- svc/svc_day_luck_draw_reward.go | 329 +++++++++++++++++++++++- svc/svc_day_luck_draw_settle_order.go | 19 ++ svc/svc_deal_user_amount.go | 126 +++++++++ svc/svc_redis_mutex_lock.go | 84 ++++++ svc/svc_redis_mutex_lock_for_amount.go | 24 ++ 21 files changed, 855 insertions(+), 37 deletions(-) create mode 100644 db/db_day_luck_draw_settle_order.go create mode 100644 db/model/day_luck_draw_settle_order.go create mode 100644 db/model/fin_user_flow.go create mode 100644 db/model/user_profile.go create mode 100644 md/app_redis_key.go create mode 100644 md/fin_user_flow.go create mode 100644 svc/svc_day_luck_draw_settle_order.go create mode 100644 svc/svc_deal_user_amount.go create mode 100644 svc/svc_redis_mutex_lock.go create mode 100644 svc/svc_redis_mutex_lock_for_amount.go diff --git a/db/db_day_luck_draw_order_jackpot.go b/db/db_day_luck_draw_order_jackpot.go index 9dbb115..42e2c33 100644 --- a/db/db_day_luck_draw_order_jackpot.go +++ b/db/db_day_luck_draw_order_jackpot.go @@ -17,9 +17,6 @@ func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { var data = &model.DayLuckDrawOrderJackpot{ Oid: req.Oid, Pvd: req.Pvd, - Amount: req.Amount, - Commission: req.Commission, - Reward: req.Reward, Uid: zhios_day_luck_draw_utils.StrToInt(req.Uid), CreateTime: time.Now(), } @@ -33,18 +30,6 @@ func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { return nil } -/*** -1.创建期数 -2.获取还没分配的金额 就是 期数为0的 -3.把期数设置到订单 -4.查出所有订单号 -5.随机出订单号(每个名额随机一次 如果重复再次循环) 先按一等奖分 -*/ - -func GetAllOrderSum(sess *xorm.Session) float64 { - sum, _ := sess.Where("period=0").Sum(&model.DayLuckDrawOrderJackpot{}, "reward") - return sum -} func GetAllOrderOid(sess *xorm.Session) []string { sql := `SELECT oid,uid FROM day_luck_draw_order_jackpot where period=0;` data, _ := QueryNativeStringSess(sess, sql) diff --git a/db/db_day_luck_draw_period.go b/db/db_day_luck_draw_period.go index 87d5495..e9fb248 100644 --- a/db/db_day_luck_draw_period.go +++ b/db/db_day_luck_draw_period.go @@ -8,11 +8,12 @@ import ( "xorm.io/xorm" ) -func AddPeriod(sess *xorm.Session, req md.DayLuckDrawPeriodReq) bool { +func AddPeriod(sess *xorm.Session, req md.DayLuckDrawPeriodReq, base string) bool { var data = &model.DayLuckDrawPeriod{ Reward: req.Reward, CreateTime: time.Now(), Period: zhios_day_luck_draw_utils.StrToInt(req.Period), + Base: base, } insert, err := sess.Insert(data) if insert == 0 || err != nil { diff --git a/db/db_day_luck_draw_period_reward.go b/db/db_day_luck_draw_period_reward.go index a02f599..38ab14f 100644 --- a/db/db_day_luck_draw_period_reward.go +++ b/db/db_day_luck_draw_period_reward.go @@ -9,8 +9,8 @@ import ( "xorm.io/xorm" ) -func AddPeriodReward(eg *xorm.Engine, req md.DayLuckDrawRewardReq) error { - count, _ := eg.Where("uid=? and period=?", req.Uid, req.Period).Count(&model.DayLuckDrawPeriodReward{}) +func AddPeriodReward(sess *xorm.Session, req md.DayLuckDrawRewardReq) error { + count, _ := sess.Where("uid=? and period=?", req.Uid, req.Period).Count(&model.DayLuckDrawPeriodReward{}) if count > 0 { return nil } @@ -21,7 +21,7 @@ func AddPeriodReward(eg *xorm.Engine, req md.DayLuckDrawRewardReq) error { Period: zhios_day_luck_draw_utils.StrToInt(req.Period), Lv: zhios_day_luck_draw_utils.StrToInt(req.Lv), } - one, err := eg.InsertOne(data) + one, err := sess.Insert(data) if one == 0 { return errors.New("失败") } diff --git a/db/db_day_luck_draw_setting.go b/db/db_day_luck_draw_setting.go index 6ee2e09..8bf93d1 100644 --- a/db/db_day_luck_draw_setting.go +++ b/db/db_day_luck_draw_setting.go @@ -2,6 +2,8 @@ package db import ( "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" + zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" + "time" "xorm.io/xorm" ) @@ -19,6 +21,23 @@ func GetDayLuckDrawSetting(eg *xorm.Engine) *model.DayLuckDrawSetting { } return &data } +func CheckSetting(eg *xorm.Engine, pvd string) bool { + setting := GetDayLuckDrawSetting(eg) + if setting == nil { + return false + } + now := time.Now().Unix() + if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { + return false + } + if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { + return false + } + if setting.OrderSoruce == "mall" && pvd != "" && zhios_day_luck_draw_utils.InArr(pvd, []string{"mall_goods", "mall_group_buy", "mall_goods_user_lv", "super_group_buy", "mall_supply", "mall_group_own_buy"}) == false { + return false + } + return true +} func GetDayLuckDrawSettingSess(sess *xorm.Session) *model.DayLuckDrawSetting { var data model.DayLuckDrawSetting get, err := sess.Get(&data) diff --git a/db/db_day_luck_draw_settle_order.go b/db/db_day_luck_draw_settle_order.go new file mode 100644 index 0000000..b248eaf --- /dev/null +++ b/db/db_day_luck_draw_settle_order.go @@ -0,0 +1,38 @@ +package db + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" + zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" + "errors" + "time" + "xorm.io/xorm" +) + +func GetSettleAllOrderSum(sess *xorm.Session) float64 { + sum, _ := sess.Where("is_send=0").Sum(&model.DayLuckDrawSettleOrder{}, "commission") + return sum +} + +func AddSettle(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { + count, _ := eg.Where("oid=? and uid=? and pvd=?", req.Oid, req.Uid, req.Pvd).Count(&model.DayLuckDrawSettleOrder{}) + if count > 0 { + return nil + } + var data = &model.DayLuckDrawSettleOrder{ + Oid: req.Oid, + Pvd: req.Pvd, + Amount: req.Amount, + Commission: req.Commission, + Uid: zhios_day_luck_draw_utils.StrToInt(req.Uid), + CreateTime: time.Now(), + } + one, err := eg.InsertOne(data) + if one == 0 { + return errors.New("失败") + } + if err != nil { + return err + } + return nil +} diff --git a/db/db_user.go b/db/db_user.go index f4786bc..8d445a6 100644 --- a/db/db_user.go +++ b/db/db_user.go @@ -14,3 +14,12 @@ func UserFindByMobile(Db *xorm.Engine, mobile string) (*model.User, error) { } return &m, nil } + +func UserProfileFindByIDWithSession(sess *xorm.Session, id interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := sess.Where("uid = ?", id). + Get(&m); err != nil || has == false { + return nil, err + } + return &m, nil +} diff --git a/db/model/day_luck_draw_order_jackpot.go b/db/model/day_luck_draw_order_jackpot.go index 9c2b28e..5d60fe1 100644 --- a/db/model/day_luck_draw_order_jackpot.go +++ b/db/model/day_luck_draw_order_jackpot.go @@ -8,9 +8,6 @@ type DayLuckDrawOrderJackpot struct { Id int `json:"id" xorm:"not null pk autoincr INT(11)"` Oid string `json:"oid" xorm:"index unique(oid_pvd) VARCHAR(255)"` Pvd string `json:"pvd" xorm:"unique(oid_pvd) index VARCHAR(255)"` - Amount string `json:"amount" xorm:"DECIMAL(11,6)"` - Commission string `json:"commission" xorm:"DECIMAL(11,6)"` - Reward string `json:"reward" xorm:"DECIMAL(11,6)"` Uid int `json:"uid" xorm:"index INT(11)"` CreateTime time.Time `json:"create_time" xorm:"DATETIME"` Period int `json:"period" xorm:"default 0 INT(11)"` diff --git a/db/model/day_luck_draw_period.go b/db/model/day_luck_draw_period.go index af0710d..1465eeb 100644 --- a/db/model/day_luck_draw_period.go +++ b/db/model/day_luck_draw_period.go @@ -7,6 +7,7 @@ import ( type DayLuckDrawPeriod struct { Id int `json:"id" xorm:"not null pk autoincr INT(11)"` Reward string `json:"reward" xorm:"VARCHAR(255)"` + Base string `json:"base" xorm:"TEXT"` CreateTime time.Time `json:"create_time" xorm:"DATETIME"` Period int `json:"period" xorm:"default 0 INT(11)"` } diff --git a/db/model/day_luck_draw_settle_order.go b/db/model/day_luck_draw_settle_order.go new file mode 100644 index 0000000..229144d --- /dev/null +++ b/db/model/day_luck_draw_settle_order.go @@ -0,0 +1,16 @@ +package model + +import ( + "time" +) + +type DayLuckDrawSettleOrder struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + Oid string `json:"oid" xorm:"index unique(oid_pvd) VARCHAR(255)"` + Pvd string `json:"pvd" xorm:"unique(oid_pvd) index VARCHAR(255)"` + Amount string `json:"amount" xorm:"DECIMAL(11,6)"` + Commission string `json:"commission" xorm:"DECIMAL(11,6)"` + Uid int `json:"uid" xorm:"index INT(11)"` + CreateTime time.Time `json:"create_time" xorm:"DATETIME"` + IsSend int `json:"is_send" xorm:"default 0 INT(11)"` +} diff --git a/db/model/fin_user_flow.go b/db/model/fin_user_flow.go new file mode 100644 index 0000000..da8a443 --- /dev/null +++ b/db/model/fin_user_flow.go @@ -0,0 +1,29 @@ +package model + +import ( + "time" +) + +type FinUserFlow struct { + Id int64 `json:"id" xorm:"pk autoincr comment('流水编号') BIGINT(20)"` + Uid int `json:"uid" xorm:"not null default 0 comment('用户id') INT(11)"` + Type int `json:"type" xorm:"not null default 0 comment('0收入,1支出') TINYINT(1)"` + Amount string `json:"amount" xorm:"not null default 0.0000 comment('变动金额') DECIMAL(11,4)"` + BeforeAmount string `json:"before_amount" xorm:"not null default 0.0000 comment('变动前金额') DECIMAL(11,4)"` + AfterAmount string `json:"after_amount" xorm:"not null default 0.0000 comment('变动后金额') DECIMAL(11,4)"` + SysFee string `json:"sys_fee" xorm:"not null default 0.0000 comment('手续费') DECIMAL(11,4)"` + PaymentType int `json:"payment_type" xorm:"not null default 1 comment('1支付宝,2微信.3手动转账') TINYINT(1)"` + OrdType string `json:"ord_type" xorm:"not null default '' comment('订单类型taobao,jd,pdd,vip,suning,kaola,own自营,withdraw提现') VARCHAR(20)"` + OrdId string `json:"ord_id" xorm:"not null default '' comment('对应订单编号') VARCHAR(50)"` + OrdTitle string `json:"ord_title" xorm:"not null default '' comment('订单标题') VARCHAR(50)"` + OrdAction int `json:"ord_action" xorm:"not null default 0 comment('10自购,11推广,12团队,20提现,21消费') TINYINT(2)"` + OrdTime int `json:"ord_time" xorm:"not null default 0 comment('下单时间or提现时间') INT(11)"` + OrdDetail string `json:"ord_detail" xorm:"not null default '' comment('记录商品ID或提现账号') VARCHAR(50)"` + ExpectedTime string `json:"expected_time" xorm:"not null default '0' comment('预期到账时间,字符串用于直接显示,结算后清除内容') VARCHAR(30)"` + State int `json:"state" xorm:"not null default 1 comment('1未到账,2已到账') TINYINT(1)"` + Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(2000)"` + OtherId int64 `json:"other_id" xorm:"not null default 0 comment('其他关联订单,具体根据订单类型判断') BIGINT(20)"` + AliOrdId string `json:"ali_ord_id" xorm:"default '' comment('支付宝订单号') VARCHAR(128)"` + CreateAt time.Time `json:"create_at" xorm:"created not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` +} diff --git a/db/model/user_profile.go b/db/model/user_profile.go new file mode 100644 index 0000000..3bd7fe1 --- /dev/null +++ b/db/model/user_profile.go @@ -0,0 +1,91 @@ +package model + +import ( + "time" +) + +type UserProfile struct { + Uid int `json:"uid" xorm:"not null pk comment('关联userID') INT(20)"` + ArkidUid int `json:"arkid_uid" xorm:"not null default 0 comment('Arkid 用户ID') INT(20)"` + ParentUid int `json:"parent_uid" xorm:"not null default 0 comment('上级ID') INT(20)"` + ArkidToken string `json:"arkid_token" xorm:"not null default '' comment('token') VARCHAR(2000)"` + AvatarUrl string `json:"avatar_url" xorm:"not null default '' comment('头像URL') VARCHAR(2000)"` + CustomInviteCode string `json:"custom_invite_code" xorm:"not null default '' comment('邀请码(自定义)') VARCHAR(16)"` + InviteCode string `json:"invite_code" xorm:"not null default '' comment('邀请码(系统)') VARCHAR(16)"` + Gender int `json:"gender" xorm:"not null default 2 comment('性别0女,1男,2未知') TINYINT(1)"` + Birthday int `json:"birthday" xorm:"not null default 0 comment('出生日期') INT(10)"` + AccWxId string `json:"acc_wx_id" xorm:"not null default '' comment('账户_微信id') VARCHAR(50)"` + AccWxOpenid string `json:"acc_wx_openid" xorm:"not null default '' comment('账户_微信openid') VARCHAR(80)"` + AccTaobaoNickname string `json:"acc_taobao_nickname" xorm:"not null default '' comment('淘宝昵称') VARCHAR(50)"` + AccTaobaoAuthTime int64 `json:"acc_taobao_auth_time" xorm:"not null default 0 comment('淘宝授权备案时间') BIGINT(11)"` + AccTaobaoShareId int64 `json:"acc_taobao_share_id" xorm:"not null default 0 comment('淘宝分享relationId,') index BIGINT(12)"` + AccTaobaoSelfId int64 `json:"acc_taobao_self_id" xorm:"not null default 0 comment('淘宝自购specialId') index BIGINT(12)"` + AccJdSelfId string `json:"acc_jd_self_id" xorm:"not null default '' comment('京东自购ID') index VARCHAR(50)"` + AccJdShareId string `json:"acc_jd_share_id" xorm:"not null default '' comment('京东分享ID') index VARCHAR(50)"` + AccJdFreeId string `json:"acc_jd_free_id" xorm:"not null default '' comment('京东新人免单ID') VARCHAR(50)"` + AccSuningSelfId string `json:"acc_suning_self_id" xorm:"not null default '' comment('苏宁自购ID') index VARCHAR(50)"` + AccSuningShareId string `json:"acc_suning_share_id" xorm:"not null default '' comment('苏宁分享ID') index VARCHAR(50)"` + AccSuningFreeId string `json:"acc_suning_free_id" xorm:"not null default '' comment('苏宁新人免单ID') VARCHAR(50)"` + AccPddSelfId string `json:"acc_pdd_self_id" xorm:"not null default '' comment('拼多多自购ID') index VARCHAR(50)"` + AccPddShareId string `json:"acc_pdd_share_id" xorm:"not null default '' comment('拼多多分享ID') index VARCHAR(50)"` + AccPddFreeId string `json:"acc_pdd_free_id" xorm:"not null default '' comment('拼多多新人免单ID') VARCHAR(50)"` + AccPddBind int `json:"acc_pdd_bind" xorm:"not null default 0 comment('拼多多是否授权绑定') TINYINT(1)"` + AccVipSelfId string `json:"acc_vip_self_id" xorm:"not null default '' comment('唯品会自购ID') index VARCHAR(50)"` + AccVipShareId string `json:"acc_vip_share_id" xorm:"not null default '' comment('唯品会分享ID') index VARCHAR(50)"` + AccVipFreeId string `json:"acc_vip_free_id" xorm:"not null default '' comment('唯品会新人免单ID') VARCHAR(50)"` + AccKaolaSelfId string `json:"acc_kaola_self_id" xorm:"not null default '' comment('考拉自购ID') index VARCHAR(50)"` + AccKaolaShareId string `json:"acc_kaola_share_id" xorm:"not null default '' comment('考拉分享ID') index VARCHAR(50)"` + AccKaolaFreeId string `json:"acc_kaola_free_id" xorm:"not null default '' comment('考拉新人免单ID') VARCHAR(50)"` + AccDuomaiShareId int64 `json:"acc_duomai_share_id" xorm:"not null pk default 0 comment('多麦联盟分享ID') BIGINT(12)"` + AccAlipay string `json:"acc_alipay" xorm:"not null default '' comment('支付宝账号') VARCHAR(50)"` + AccAlipayRealName string `json:"acc_alipay_real_name" xorm:"not null default '' comment('支付宝账号真实姓名') VARCHAR(50)"` + CertTime int `json:"cert_time" xorm:"not null default 0 comment('认证时间') INT(10)"` + CertName string `json:"cert_name" xorm:"not null default '' comment('证件上名字,也是真实姓名') VARCHAR(50)"` + CertNum string `json:"cert_num" xorm:"not null default '' comment('证件号码') VARCHAR(50)"` + CertState int `json:"cert_state" xorm:"not null default 0 comment('认证状态(0为未认证,1为认证中,2为已认证,3为认证失败)') TINYINT(1)"` + FinCommission string `json:"fin_commission" xorm:"not null default 0.0000 comment('累计佣金') DECIMAL(10,4)"` + FinValid string `json:"fin_valid" xorm:"not null default 0.0000 comment('可用余额,fin=>finance财务') DECIMAL(10,4)"` + FinInvalid string `json:"fin_invalid" xorm:"not null default 0.0000 comment('不可用余额,冻结余额') DECIMAL(10,4)"` + FinSelfOrderCount int `json:"fin_self_order_count" xorm:"not null default 0 comment('自购订单数,包括未完成') INT(11)"` + FinSelfOrderCountDone int `json:"fin_self_order_count_done" xorm:"not null default 0 comment('自购已完成订单') INT(11)"` + FinSelfRebate float32 `json:"fin_self_rebate" xorm:"not null default 0.000000 comment('累积自购获得返利金额') FLOAT(14,6)"` + FinTotal float32 `json:"fin_total" xorm:"not null default 0.000000 comment('累计总收益') FLOAT(14,6)"` + Lat float32 `json:"lat" xorm:"not null default 0.000000 comment('纬度') FLOAT(15,6)"` + Lng float32 `json:"lng" xorm:"not null default 0.000000 comment('经度') FLOAT(15,6)"` + Memo string `json:"memo" xorm:"not null default '' comment('用户简述备注') VARCHAR(2048)"` + IsNew int `json:"is_new" xorm:"not null default 1 comment('是否是新用户') TINYINT(1)"` + IsVerify int `json:"is_verify" xorm:"not null default 0 comment('是否有效会员') TINYINT(1)"` + IsOrdered int `json:"is_ordered" xorm:"not null default 0 comment('是否已完成首单(0否,1是)') TINYINT(1)"` + FromWay string `json:"from_way" xorm:"not null default '' comment('注册来源: +no_captcha_phone:免验证码手机号注册; +manual_phone:手动手机验证码注册; +wx:微信授权; +wx_mp:小程序授权; +wx_pub:公众号授权; +wx_bind_phone:微信注册绑定手机号; +admin:管理员添加;taobao_bind_phone:淘宝注册绑定手机号,apple_bind_phone:苹果注册绑定手机号') VARCHAR(16)"` + HidOrder int `json:"hid_order" xorm:"not null default 0 comment('隐藏订单') TINYINT(3)"` + HidContact int `json:"hid_contact" xorm:"not null default 0 comment('隐藏联系方式') TINYINT(4)"` + NewMsgNotice int `json:"new_msg_notice" xorm:"not null default 1 comment('新消息通知') TINYINT(1)"` + WxAccount string `json:"wx_account" xorm:"not null default '' comment('微信号') VARCHAR(100)"` + WxQrcode string `json:"wx_qrcode" xorm:"not null default '' comment('微信二维码') VARCHAR(100)"` + ThirdPartyTaobaoOid string `json:"third_party_taobao_oid" xorm:"not null default '' comment('淘宝第三方登录openID') VARCHAR(100)"` + ThirdPartyTaobaoSid string `json:"third_party_taobao_sid" xorm:"not null default '' comment('淘宝第三方登录sID') VARCHAR(255)"` + ThirdPartyTaobaoAcctoken string `json:"third_party_taobao_acctoken" xorm:"not null default '' comment('淘宝第三方登录topaccesstoken') VARCHAR(100)"` + ThirdPartyTaobaoAuthcode string `json:"third_party_taobao_authcode" xorm:"not null default '' comment('淘宝第三方登录topAuthCode') VARCHAR(100)"` + ThirdPartyAppleToken string `json:"third_party_apple_token" xorm:"not null default '' comment('苹果第三方登录token') VARCHAR(1024)"` + ThirdPartyQqAccessToken string `json:"third_party_qq_access_token" xorm:"not null default '' comment('QQ第三方登录access_token') VARCHAR(255)"` + ThirdPartyQqExpiresIn string `json:"third_party_qq_expires_in" xorm:"not null default '' comment('QQ第三方登录expires_in(剩余时长)') VARCHAR(255)"` + ThirdPartyQqOpenid string `json:"third_party_qq_openid" xorm:"not null default '' comment('QQ第三方登陆openid(不变,用于认证)') VARCHAR(255)"` + ThirdPartyQqUnionid string `json:"third_party_qq_unionid" xorm:"not null default '' comment('QQ第三方登陆unionid') VARCHAR(255)"` + ThirdPartyWechatExpiresIn string `json:"third_party_wechat_expires_in" xorm:"not null default '' comment('微信第三方登录expires_in(剩余时长)') VARCHAR(255)"` + ThirdPartyWechatOpenid string `json:"third_party_wechat_openid" xorm:"not null default '' comment('微信第三方登陆openid(不变,用于认证)') VARCHAR(255)"` + ThirdPartyWechatUnionid string `json:"third_party_wechat_unionid" xorm:"not null default '' comment('微信第三方登陆unionid') VARCHAR(255)"` + ThirdPartyWechatMiniOpenid string `json:"third_party_wechat_mini_openid" xorm:"not null default '' comment('微信小程序登录open_id') VARCHAR(255)"` + ThirdPartyWechatH5Openid string `json:"third_party_wechat_h5_openid" xorm:"not null default '' comment('微信H5登录open_id') VARCHAR(255)"` + FreeRemainTime int `json:"free_remain_time" xorm:"not null default 0 comment('免单剩余次数') INT(11)"` + FreeCumulativeTime int `json:"free_cumulative_time" xorm:"not null default 0 comment('免单累计次数') INT(11)"` + IsDelete int `json:"is_delete" xorm:"not null default 0 comment('是否已删除') TINYINT(1)"` + UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` + SignDay int `json:"sign_day" xorm:"not null default 0 comment('签到天数') INT(11)"` +} diff --git a/go.mod b/go.mod index f286972..4cedaaa 100644 --- a/go.mod +++ b/go.mod @@ -9,4 +9,5 @@ require ( go.uber.org/zap v1.13.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 xorm.io/xorm v1.3.1 + github.com/shopspring/decimal v1.3.1 ) diff --git a/md/app_redis_key.go b/md/app_redis_key.go new file mode 100644 index 0000000..af03a8f --- /dev/null +++ b/md/app_redis_key.go @@ -0,0 +1,20 @@ +package md + +// 缓存key统一管理, %s格式化为masterId +const ( + AppCfgCacheKey = "%s:cfg_cache:%s" // 占位符: masterId, key的第一个字母 + VirtualCoinCfgCacheKey = "%s:virtual_coin_cfg" + PlanRewardCfgCacheKey = "%s:plan_reward_cfg" + UnionSetCacheCfg = "%s:union_set_cfg:%s" // 联盟设置缓存key + + UserFinValidUpdateLock = "%s:user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额) + UserVirtualAmountUpdateLock = "%s:user_virtual_amount_update_lock:%s" // 用户虚拟币更新锁(能拿到锁才能更新余额) + + WithdrawApplyQueueListKey = "withdraw_apply_queue" // 提现队列 + + TplBottomNavRedisKey = "%s:tpl_nav_bottom_key:%s" // master_id platform + + SysModByIdRedisKey = "%s:sys_mod_tpl_by_id:%s" + + CfgCacheTime = 86400 +) diff --git a/md/day_luck_draw_setting.go b/md/day_luck_draw_setting.go index 65ffecc..36210dd 100644 --- a/md/day_luck_draw_setting.go +++ b/md/day_luck_draw_setting.go @@ -4,4 +4,5 @@ type RewardData struct { Key string `json:"key"` Bili string `json:"bili"` Num string `json:"num"` + Probability string `json:"probability"` } diff --git a/md/fin_user_flow.go b/md/fin_user_flow.go new file mode 100644 index 0000000..21f5dc2 --- /dev/null +++ b/md/fin_user_flow.go @@ -0,0 +1,45 @@ +package md + +const ( + FinUserFlowDirectionIncome = 1 //流水 - 收入 + FinUserFlowDirectionExpenditure = 2 //流水 - 支出 +) + +const ( + FinUserFlowRedisDataBase = 0 + FinUserFlowRedisKey = "%s:fin_user_flow:%d:user:%d" +) + +const ( + IntegralReleaseServiceRevenueTitleForFinUserFlow = "积分释放-服务收益" + IntegralReleaseServiceRevenueRefundTitleForFinUserFlow = "订单退款-服务收益扣除" +) + +const ( + IntegralReleaseServiceRevenueOrderTypeForFinUserFlow = 50 // 积分释放-服务收益 + IntegralReleaseServiceRevenueOrderRefundTypeForFinUserFlow = 51 // 积分释放-服务收益退款 +) + +const DealUserAmountRequestIdPrefix = "%s:deal_user_amount:%d" +const UserAmountRedisKey = "%s:user_amount:%d" + +type DealIntegralReleaseInterpositionUserAmountReq struct { + Kind string `json:"kind"` + Mid string `json:"mid"` + OrdId string `json:"ord_id"` + CoinId int `json:"coin_id"` + Uid int `json:"uid"` + OriginalUid int `json:"original_uid"` + Amount float64 `json:"amount"` +} + +type DealUserAmount struct { + Kind string `json:"kind"` + Mid string `json:"mid"` + Title string `json:"title"` + OrderType string `json:"order_type"` + OrdAction int `json:"ord_action"` + OrdId string `json:"ord_id"` + Uid int `json:"uid"` + Amount float64 `json:"amount"` +} diff --git a/svc/svc_day_luck_draw_order_jackpot.go b/svc/svc_day_luck_draw_order_jackpot.go index 6ea52fa..d36bfba 100644 --- a/svc/svc_day_luck_draw_order_jackpot.go +++ b/svc/svc_day_luck_draw_order_jackpot.go @@ -3,21 +3,12 @@ package svc import ( "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" - zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" - "time" "xorm.io/xorm" ) func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { - setting := db.GetDayLuckDrawSetting(eg) - if setting == nil { - return nil - } - now := time.Now().Unix() - if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() || (now > setting.StartTime.Unix() && now < setting.EndTime.Unix()) { - return nil - } - if setting.OrderSoruce == "mall" && zhios_day_luck_draw_utils.InArr(req.Pvd, []string{"mall_goods", "mall_group_buy", "mall_goods_user_lv", "super_group_buy", "mall_supply", "mall_group_own_buy"}) == false { + setting := db.CheckSetting(eg, req.Pvd) + if setting == false { return nil } err := db.AddOrderJackpot(eg, req) diff --git a/svc/svc_day_luck_draw_reward.go b/svc/svc_day_luck_draw_reward.go index 144a247..5945833 100644 --- a/svc/svc_day_luck_draw_reward.go +++ b/svc/svc_day_luck_draw_reward.go @@ -2,14 +2,27 @@ package svc import ( "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" "encoding/json" + "errors" + "fmt" + "github.com/shopspring/decimal" "math/rand" "time" "xorm.io/xorm" ) +func InitForDayLuckDraw(redisAddr string) (err error) { + if redisAddr != "" { + cache.NewRedis(redisAddr) + } + _, err = cache.SelectDb(0) + return +} + //随机几个用户 func RandUser(sess *xorm.Session) []string { var newOid = make([]string, 0) @@ -19,7 +32,10 @@ func RandUser(sess *xorm.Session) []string { return newOid } now := time.Now().Unix() - if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() || (now > setting.StartTime.Unix() && now < setting.EndTime.Unix()) { + if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { + return newOid + } + if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { return newOid } count := 0 @@ -38,6 +54,224 @@ func RandUser(sess *xorm.Session) []string { return newOid } + +/*** +1.创建期数 +2.获取还没分配的金额 就是 期数为0的 +3.把期数设置到订单 +4.查出所有订单号 +5.随机出订单号(每个名额随机一次 如果重复再次循环) 按概率分几等奖 +*/ + +func GetUserReward(eg *xorm.Engine, mid string, isTask bool) error { + // 加锁 防止频繁操作 + mutexKey := fmt.Sprintf("%s:day_lucky_raw_settle", mid) + operationSumAvailable, err := cache.Do("SET", mutexKey, 1, "EX", 3600, "NX") + if err != nil { + return err + } + defer cache.Del(mutexKey) + if operationSumAvailable != "OK" { + return errors.New("上一次未运行完成") + } + sess := eg.NewSession() + defer func() { + sess.Close() + if err := recover(); err != nil { + fmt.Println(err) + } + }() + sess.Begin() + key := fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) + isDone, _ := cache.GetString(key) + if isDone == "" || isDone == "0" { + SetAllAwardsProbability(sess, mid) + } + probabilityMap := make([]map[int]int64, 0) + key = fmt.Sprintf("%s:day_lucky_draw_rotary_bingo_rate", mid) + err = cache.GetJson(key, &probabilityMap) + if err != nil { + sess.Rollback() + return err + } + + setting := db.GetDayLuckDrawSettingSess(sess) + var rewardData = make([]md.RewardData, 0) + err = json.Unmarshal([]byte(setting.RewardData), &rewardData) + if err != nil { + sess.Rollback() + return err + } + now := time.Now().Unix() + if isTask { + if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { + return errors.New("未开始") + } + if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { + return errors.New("未开始") + } + if setting.OpenTime.IsZero() { + return errors.New("没抽奖时间") + } + if now < setting.OpenTime.Unix() { + return errors.New("没到时间") + } + } + if setting.Source == "" { + return errors.New("未选择奖励池数据类型") + } + //设置期数 + max := db.GetPeriodMax(sess) + sum := db.GetSettleAllOrderSum(sess) + if setting.Source == "amount" { + sum = zhios_day_luck_draw_utils.StrToFloat64(setting.Amount) + } else { + sum = sum * zhios_day_luck_draw_utils.StrToFloat64(setting.CommissionBili) / 100 + } + if sum == 0 { //没金额中断了 + setting.OpenTime = time.Unix(now+int64(setting.CycleDay)*86400, 0) + update, err := sess.Where("id=?", setting.Id).Cols("open_time").Update(setting) + if err != nil || update == 0 { + sess.Rollback() + return errors.New("失败") + } + sess.Commit() + return errors.New("没金额") + } + period := 1 + if max != nil { + period = max.Period + 1 + } + req := md.DayLuckDrawPeriodReq{ + Reward: zhios_day_luck_draw_utils.Float64ToStrByPrec(sum, 7), + Period: zhios_day_luck_draw_utils.IntToStr(period), + } + settingStr, _ := json.Marshal(setting) + bools := db.AddPeriod(sess, req, string(settingStr)) + if bools == false { + return errors.New("期数写入错误") + } + + rewardDataMap := make(map[int64]int, 0) + for _, v := range rewardData { + rewardDataMap[zhios_day_luck_draw_utils.StrToInt64(v.Key)] = zhios_day_luck_draw_utils.StrToInt(v.Num) + } + uids := RandUser(sess) + var award = make(map[string]int64) + var awardIdMap = make(map[int64]int) + for _, v := range uids { + for i := 0; i < 10; i++ { + key := AwardRandomNumberFor100000() + awardId := int64(0) + for _, awardProbabilityMap := range probabilityMap { + id, ok := awardProbabilityMap[key] + if ok { + awardId = id + } else { + continue + } + } + if awardId == 0 || award[v] > 0 { + continue + } + //查下已产生用户数量 + awardCount, ok := awardIdMap[awardId] + //查下总数量 + rewardDataCount, ok := rewardDataMap[awardId] + if ok == false { + continue + } + if ok { + if awardCount+1 > rewardDataCount { + continue + } + } + if rewardDataCount == 0 { + continue + } + awardIdMap[awardId] = awardCount + 1 + award[v] = awardId + } + } + + //处理奖励 + var awardMap = make(map[int64][]string) + for k, v := range award { + awardMap[v] = append(awardMap[v], k) + } + for _, v := range rewardData { + uid, ok := awardMap[zhios_day_luck_draw_utils.StrToInt64(v.Key)] + if ok { + err := SendReward(sess, uid, mid, period, sum, v) + if err != nil { + sess.Rollback() + return err + } + } + } + setting.OpenTime = time.Unix(now+int64(setting.CycleDay)*86400, 0) + update, err := sess.Where("id=?", setting.Id).Cols("open_time").Update(setting) + if err != nil || update == 0 { + sess.Rollback() + return errors.New("失败") + } + update1, err1 := sess.Where("is_send=0").Cols("is_send").Update(&model.DayLuckDrawSettleOrder{IsSend: 1}) + if err1 != nil || update1 == 0 { + sess.Rollback() + return errors.New("失败") + } + update2, err2 := sess.Where("period=0").Cols("period").Update(&model.DayLuckDrawOrderJackpot{Period: period}) + if err2 != nil || update2 == 0 { + sess.Rollback() + return errors.New("失败") + } + sess.Commit() + return nil +} +func SendReward(sess *xorm.Session, uid []string, mid string, period int, sum float64, rewardData md.RewardData) error { + count := len(uid) + if count == 0 { + return nil + } + bili := zhios_day_luck_draw_utils.StrToFloat64(rewardData.Bili) + if bili == 0 { + return nil + } + amount := sum * bili / float64(count) + for _, v := range uid { + var req = md.DayLuckDrawRewardReq{ + Uid: v, + Period: zhios_day_luck_draw_utils.IntToStr(period), + Reward: zhios_day_luck_draw_utils.Float64ToStrByPrec(amount, 7), + Lv: rewardData.Key, + } + err := db.AddPeriodReward(sess, req) + if err != nil { + return err + } + var dealUserAmount = md.DealUserAmount{ + Kind: "add", + Mid: mid, + Title: "每日抽奖奖励", + OrderType: "", + OrdAction: 85, + OrdId: "", + Uid: zhios_day_luck_draw_utils.StrToInt(v), + Amount: amount, + } + err = DealUserAmount(sess, dealUserAmount) + if err != nil { + return err + } + } + return nil +} +func AwardRandomNumberFor100000() int { + rand.Seed(time.Now().UnixNano()) + num := rand.Intn(100000) + return num +} + func MicsSlice(origin []string, count int) []string { tmpOrigin := make([]string, len(origin)) copy(tmpOrigin, origin) @@ -47,12 +281,99 @@ func MicsSlice(origin []string, count int) []string { tmpOrigin[i], tmpOrigin[j] = tmpOrigin[j], tmpOrigin[i] }) - result := make([]string, 0, count) - for index, value := range tmpOrigin { - if index == count { + result := make([]string, 0) + for _, value := range tmpOrigin { + if len(result) == count { break } + if zhios_day_luck_draw_utils.InArr(value, result) { + continue + } result = append(result, value) } return result } + +func SetAllAwardsProbability(sess *xorm.Session, mid string) error { + defer func() { + //处理异常错误 + if r := recover(); r != nil { + fmt.Println(r) + } + }() + setting := db.GetDayLuckDrawSettingSess(sess) + var rewardData = make([]md.RewardData, 0) + err := json.Unmarshal([]byte(setting.RewardData), &rewardData) + if err != nil { + key := fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) + _, err = cache.SetEx(key, "0", 39528000) // 半年 + if err != nil { + return err + } + } + //建立协程池 + workerCount := 0 + ProbabilityKeyChan := make(chan int, 100000) + awardsMapChan := make(chan map[int]int64, len(rewardData)) + doneChan := make(chan bool, len(rewardData)) + for i := 0; i < 10; i++ { + go func(endNum int) { + for startNum := (endNum * 10000) + 1; startNum <= (endNum+1)*10000; startNum++ { + ProbabilityKeyChan <- startNum + } + if i == 9 { + close(ProbabilityKeyChan) + } + }(i) + } + for _, award := range rewardData { + probabilityD, err := decimal.NewFromString(award.Num) + if err != nil { + probabilityD = decimal.NewFromInt(0) + } + probabilityD = probabilityD.Div(decimal.NewFromInt(100)) + probability, _ := probabilityD.Float64() + go CalculateAwardsProbability(zhios_day_luck_draw_utils.StrToInt64(award.Key), probability, ProbabilityKeyChan, awardsMapChan, doneChan) + workerCount++ + } + probabilityMap := make([]map[int]int64, 0) + WaitChain(workerCount, awardsMapChan, doneChan) + for awards := range awardsMapChan { + probabilityMap = append(probabilityMap, awards) + } + key := fmt.Sprintf("%s:day_lucky_draw_rotary_bingo_rate", mid) + _, err = cache.SetEx(key, zhios_day_luck_draw_utils.SerializeStr(probabilityMap), 39528000) // 半年 + if err != nil { + return err + } + key = fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) + _, err = cache.SetEx(key, "1", 39528000) // 半年 + if err != nil { + return err + } + return nil +} + +func CalculateAwardsProbability(awardsId int64, probability float64, ProbabilityKeyChan chan int, awardsMapChan chan map[int]int64, doneChan chan bool) { + //计算要循环多少次 + var awardsMap = make(map[int]int64) + for i := 0; i < int(100000*probability); i++ { + key := <-ProbabilityKeyChan + awardsMap[key] = awardsId + } + awardsMapChan <- awardsMap + doneChan <- true +} + +func WaitChain(workerCount int, awardsMapChan chan map[int]int64, doneChan chan bool) { + for { + select { + case <-doneChan: + workerCount-- + if workerCount == 0 { + close(awardsMapChan) + return + } + } + } +} diff --git a/svc/svc_day_luck_draw_settle_order.go b/svc/svc_day_luck_draw_settle_order.go new file mode 100644 index 0000000..b217a72 --- /dev/null +++ b/svc/svc_day_luck_draw_settle_order.go @@ -0,0 +1,19 @@ +package svc + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" + "xorm.io/xorm" +) + +func AddSettleOrder(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { + setting := db.CheckSetting(eg, req.Pvd) + if setting == false { + return nil + } + err := db.AddSettle(eg, req) + if err != nil { + return err + } + return nil +} diff --git a/svc/svc_deal_user_amount.go b/svc/svc_deal_user_amount.go new file mode 100644 index 0000000..4a15bd0 --- /dev/null +++ b/svc/svc_deal_user_amount.go @@ -0,0 +1,126 @@ +package svc + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" + zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" + "errors" + "fmt" + "github.com/shopspring/decimal" + "strconv" + "time" + "xorm.io/xorm" +) + +// DealUserAmount 处理给用户余额 +func DealUserAmount(session *xorm.Session, req md.DealUserAmount) (err error) { + if req.Amount < 0 { + req.Amount = 0 + } + //1、分布式锁阻拦 + requestIdPrefix := fmt.Sprintf(md.DealUserAmountRequestIdPrefix, req.Mid, req.Uid) + cb, err := HandleBalanceDistributedLockForAmount(req.Mid, strconv.Itoa(req.Uid), requestIdPrefix) + if err != nil { + return err + } + if cb != nil { + defer cb() // 释放锁 + } + + //2、计算&&组装数据 + now := time.Now() + userAmount, err := GetUserAmount(session, req.Mid, req.Uid) + if err != nil { + return err + } + userAmountValue := decimal.NewFromFloat(zhios_day_luck_draw_utils.StrToFloat64(userAmount)) + amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(8) + + var finUserFlow = model.FinUserFlow{ + Uid: req.Uid, + Amount: amountValue.String(), + BeforeAmount: userAmount, + OrdType: req.OrderType, + OrdId: req.OrdId, + OrdTitle: req.Title, + OrdAction: req.OrdAction, + OrdTime: int(now.Unix()), + State: 1, + CreateAt: now, + UpdateAt: now, + } + if req.Kind == "add" { + finUserFlow.Type = 0 + finUserFlow.AfterAmount = userAmountValue.Add(amountValue).RoundFloor(8).String() + } else if req.Kind == "sub" { + finUserFlow.Type = 1 + finUserFlow.AfterAmount = userAmountValue.Sub(amountValue).RoundFloor(8).String() + } else { + err = errors.New("错误的kind类型") + return err + } + if zhios_day_luck_draw_utils.StrToFloat64(finUserFlow.AfterAmount) < 0 { + return errors.New("用户余额不足") + } + + //3、插入 `user_virtual_coin_flow` 记录 + affected, err := session.Insert(&finUserFlow) + if affected == 0 || err != nil { + return err + } + + //4、修改 `user_profile`的fin_valid值 && 及缓存 + err = SetCacheUserAmount(session, req.Mid, finUserFlow.AfterAmount, req.Uid, true) + if err != nil { + return err + } + + return nil +} + +// GetUserAmount 获取用户余额 +func GetUserAmount(session *xorm.Session, masterId string, uid int) (amount string, err error) { + redisKey := fmt.Sprintf(md.UserAmountRedisKey, masterId, uid) + amount, err = cache.GetString(redisKey) + if err != nil { + if err.Error() == "redigo: nil returned" { + userAmount, err := db.UserProfileFindByIDWithSession(session, uid) + if err != nil { + return amount, err + } + if userAmount == nil { + amount = "0" + } else { + amount = userAmount.FinValid + } + //将获取到的余额值缓存至redis + _ = SetCacheUserAmount(session, masterId, amount, uid, false) + return amount, nil + } + return amount, err + } + return amount, nil +} + +// SetCacheUserAmount 设置缓存的用户余额 +func SetCacheUserAmount(session *xorm.Session, masterId, amount string, uid int, isUpdateDb bool) error { + redisKey := fmt.Sprintf(md.UserAmountRedisKey, masterId, uid) + if isUpdateDb { + _, err := session.Where("uid=?", uid).Update(model.UserProfile{ + Uid: uid, + FinValid: amount, + }) + if err != nil { + return err + } + } + //_, err := cache.Set(redisKey, int64(utils.StrToFloat64(amount))) + //TODO::默认缓存1小时 (先调整为 2 min) + _, err := cache.SetEx(redisKey, zhios_day_luck_draw_utils.StrToFloat64(amount), 60*2) + if err != nil { + return err + } + return nil +} diff --git a/svc/svc_redis_mutex_lock.go b/svc/svc_redis_mutex_lock.go new file mode 100644 index 0000000..f4a034d --- /dev/null +++ b/svc/svc_redis_mutex_lock.go @@ -0,0 +1,84 @@ +package svc + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" + zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" + "errors" + "fmt" + "math/rand" + "reflect" + "time" +) + +const redisMutexLockExpTime = 15 + +// TryGetDistributedLock 分布式锁获取 +// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一 +func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool { + if isNegative { // 多次尝试获取 + retry := 1 + for { + ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") + // 获取锁成功 + if err == nil && ok == "OK" { + return true + } + // 尝试多次没获取成功 + if retry > 10 { + return false + } + time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))) + retry += 1 + } + } else { // 只尝试一次 + ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") + // 获取锁成功 + if err == nil && ok == "OK" { + return true + } + + return false + } +} + +// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型 +func ReleaseDistributedLock(lockKey, requestId string) (bool, error) { + luaScript := ` + if redis.call("get",KEYS[1]) == ARGV[1] + then + return redis.call("del",KEYS[1]) + else + return 0 + end` + + do, err := cache.Do("eval", luaScript, 1, lockKey, requestId) + fmt.Println(reflect.TypeOf(do)) + fmt.Println(do) + if zhios_day_luck_draw_utils.AnyToInt64(do) == 1 { + return true, err + } else { + return false, err + } +} + +func GetDistributedLockRequestId(prefix string) string { + return prefix + zhios_day_luck_draw_utils.IntToStr(rand.Intn(100000000)) +} + +// HandleDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 +func HandleDistributedLock(masterId, uid, requestIdPrefix string) (cb func(), err error) { + // 获取余额更新锁 + balanceLockKey := fmt.Sprintf(md.UserVirtualAmountUpdateLock, masterId, uid) + requestId := GetDistributedLockRequestId(requestIdPrefix) + balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) + if !balanceLockOk { + return nil, errors.New("系统繁忙,请稍后再试") + } + + cb = func() { + _, _ = ReleaseDistributedLock(balanceLockKey, requestId) + } + + return cb, nil +} diff --git a/svc/svc_redis_mutex_lock_for_amount.go b/svc/svc_redis_mutex_lock_for_amount.go new file mode 100644 index 0000000..b300813 --- /dev/null +++ b/svc/svc_redis_mutex_lock_for_amount.go @@ -0,0 +1,24 @@ +package svc + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" + "errors" + "fmt" +) + +// HandleBalanceDistributedLockForAmount 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 +func HandleBalanceDistributedLockForAmount(masterId, uid, requestIdPrefix string) (cb func(), err error) { + // 获取余额更新锁 + balanceLockKey := fmt.Sprintf(md.UserFinValidUpdateLock, masterId, uid) + requestId := GetDistributedLockRequestId(requestIdPrefix) + balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) + if !balanceLockOk { + return nil, errors.New("系统繁忙,请稍后再试") + } + + cb = func() { + _, _ = ReleaseDistributedLock(balanceLockKey, requestId) + } + + return cb, nil +}