This commit is contained in:
parent
3e9bb2b762
commit
d091564610
|
|
@ -62,7 +62,7 @@ func (v *VoucherBiz) alarmText(_ context.Context, order *bo.OrderBo, errMsg stri
|
||||||
"</font> \n" +
|
"</font> \n" +
|
||||||
"<font color='black'>" +
|
"<font color='black'>" +
|
||||||
"不好了,订单发放发生异常了" +
|
"不好了,订单发放发生异常了" +
|
||||||
"[<font color='red'>%s</font>]请尽快处理@相关人员。" +
|
"[<font color='red'>%s</font>]" +
|
||||||
"</font>"
|
"</font>"
|
||||||
|
|
||||||
return fmt.Sprintf(msg, remarks)
|
return fmt.Sprintf(msg, remarks)
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ func (v *VoucherBiz) timeSliceQuery(ctx context.Context, startTime, endTime time
|
||||||
duration := 2 * time.Hour
|
duration := 2 * time.Hour
|
||||||
|
|
||||||
eg := new(errgroup.Group)
|
eg := new(errgroup.Group)
|
||||||
eg.SetLimit(8)
|
eg.SetLimit(10)
|
||||||
|
|
||||||
for start := startTime; start.Before(endTime); start = start.Add(duration) {
|
for start := startTime; start.Before(endTime); start = start.Add(duration) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package do
|
package do
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type WarningBudget struct {
|
type WarningBudget struct {
|
||||||
StockName string // 券名称
|
StockName string // 券名称
|
||||||
StockId string // 券ID
|
StockId string // 券ID
|
||||||
|
|
@ -12,3 +14,9 @@ type WarningBudget struct {
|
||||||
AvailableStock int64 // 可用库存
|
AvailableStock int64 // 可用库存
|
||||||
RemainingBudget int64 // 剩余预算
|
RemainingBudget int64 // 剩余预算
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WarningBudgetLog struct {
|
||||||
|
WarningBudget *WarningBudget
|
||||||
|
Num int
|
||||||
|
LastTime time.Time
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ const (
|
||||||
ProductQueryLockKey CacheKey = "product_query_lock"
|
ProductQueryLockKey CacheKey = "product_query_lock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
WarningBudgetSendIncr CacheKey = "warning_budget_send_incr"
|
||||||
|
)
|
||||||
|
|
||||||
var CacheKeyMap = map[CacheKey]time.Duration{
|
var CacheKeyMap = map[CacheKey]time.Duration{
|
||||||
CmbOrderLockKey: 30 * time.Second,
|
CmbOrderLockKey: 30 * time.Second,
|
||||||
CmbQueryLockKey: 30 * time.Second,
|
CmbQueryLockKey: 30 * time.Second,
|
||||||
|
|
@ -43,6 +47,8 @@ var CacheKeyMap = map[CacheKey]time.Duration{
|
||||||
|
|
||||||
ProductQueryKey: 30 * 86400 * time.Second, // 30天
|
ProductQueryKey: 30 * 86400 * time.Second, // 30天
|
||||||
ProductQueryLockKey: 30 * time.Second,
|
ProductQueryLockKey: 30 * time.Second,
|
||||||
|
|
||||||
|
WarningBudgetSendIncr: 1 * time.Hour,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package biz
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"voucher/internal/biz/cmb"
|
"voucher/internal/biz/cmb"
|
||||||
|
"voucher/internal/biz/do"
|
||||||
"voucher/internal/biz/mixrepos"
|
"voucher/internal/biz/mixrepos"
|
||||||
"voucher/internal/biz/repo"
|
"voucher/internal/biz/repo"
|
||||||
"voucher/internal/biz/wechatrepo"
|
"voucher/internal/biz/wechatrepo"
|
||||||
|
|
@ -26,6 +27,7 @@ type VoucherBiz struct {
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
queryMap map[string]bool
|
queryMap map[string]bool
|
||||||
|
warningBudgeMap map[string]*do.WarningBudgetLog
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVoucherBiz(
|
func NewVoucherBiz(
|
||||||
|
|
@ -57,6 +59,7 @@ func NewVoucherBiz(
|
||||||
CmbMixRepo: CmbMixRepo,
|
CmbMixRepo: CmbMixRepo,
|
||||||
|
|
||||||
queryMap: make(map[string]bool),
|
queryMap: make(map[string]bool),
|
||||||
|
warningBudgeMap: make(map[string]*do.WarningBudgetLog),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,93 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"voucher/internal/biz/bo"
|
"voucher/internal/biz/bo"
|
||||||
"voucher/internal/biz/do"
|
"voucher/internal/biz/do"
|
||||||
|
"voucher/internal/biz/vo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (s *VoucherBiz) WarningBudgetIncr(ctx context.Context, uid string) (int64, error) {
|
||||||
|
|
||||||
|
v := vo.WarningBudgetSendIncr.BuildCache([]string{uid})
|
||||||
|
|
||||||
|
// 增加发送计数
|
||||||
|
count, err := s.rdb.Rdb.IncrBy(ctx, v.Key, 1).Result()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是第一次发送,设置 过期时间
|
||||||
|
if count == 1 {
|
||||||
|
if err = s.rdb.Rdb.Expire(ctx, v.Key, v.TTL).Err(); err != nil {
|
||||||
|
return 0, fmt.Errorf("设置过期时间失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果发送次数超过 6 条,限制发送
|
||||||
|
if count > 6 {
|
||||||
|
if _, err = s.rdb.Rdb.Del(ctx, v.Key).Result(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *VoucherBiz) WarningBudgetGet(uid string) *do.WarningBudgetLog {
|
||||||
|
|
||||||
|
if w, ok := this.warningBudgeMap[uid]; ok {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *VoucherBiz) WarningBudgetSet(req *do.WarningBudget) {
|
||||||
|
|
||||||
|
this.warningBudgeMap[req.StockId] = &do.WarningBudgetLog{
|
||||||
|
WarningBudget: req,
|
||||||
|
Num: 1, // 默认1
|
||||||
|
LastTime: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *VoucherBiz) WarningBudgetAdd(req *do.WarningBudget) *do.WarningBudgetLog {
|
||||||
|
|
||||||
|
this.mu.Lock()
|
||||||
|
defer this.mu.Unlock()
|
||||||
|
|
||||||
|
w := this.WarningBudgetGet(req.StockId)
|
||||||
|
if w == nil {
|
||||||
|
this.WarningBudgetSet(req)
|
||||||
|
} else {
|
||||||
|
w.LastTime = time.Now()
|
||||||
|
w.Num += 1
|
||||||
|
w.WarningBudget = req
|
||||||
|
}
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *VoucherBiz) WarningBudgetRemove(uid string) {
|
||||||
|
|
||||||
|
this.mu.Lock()
|
||||||
|
defer this.mu.Unlock()
|
||||||
|
|
||||||
|
if _, ok := this.warningBudgeMap[uid]; ok {
|
||||||
|
delete(this.warningBudgeMap, uid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (v *VoucherBiz) WarningBudget(ctx context.Context) {
|
func (v *VoucherBiz) WarningBudget(ctx context.Context) {
|
||||||
|
|
||||||
|
uid := "warningBudget"
|
||||||
|
|
||||||
|
if b := v.Get(uid); b {
|
||||||
|
log.Warn("预警查询,上波还未执行完毕,此次暂不执行")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Add(uid)
|
||||||
|
defer v.Remove(uid)
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Warnf("预警查询,执行开始: %s", start.Format(time.DateTime))
|
log.Warnf("预警查询,执行开始: %s", start.Format(time.DateTime))
|
||||||
|
|
||||||
|
|
@ -80,24 +163,40 @@ func (v *VoucherBiz) Calculate(ctx context.Context, product *bo.ProductBo, wxRes
|
||||||
log.Warnf("预警查询,券预算明细,%s", str)
|
log.Warnf("预警查询,券预算明细,%s", str)
|
||||||
|
|
||||||
if product.WarningBudget >= remainingBudget {
|
if product.WarningBudget >= remainingBudget {
|
||||||
|
|
||||||
|
count, err := v.WarningBudgetIncr(ctx, req.StockId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if count == 1 {
|
||||||
return v.WarningSend(ctx, str)
|
return v.WarningSend(ctx, str)
|
||||||
|
} else {
|
||||||
|
log.Warnf("预警查询,当前达到预警第[%d]次,暂不做通知", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
//w := v.WarningBudgetAdd(req)
|
||||||
|
//if w.Num == 1 {
|
||||||
|
// return v.WarningSend(ctx, str)
|
||||||
|
//} else if w.Num > 5 {
|
||||||
|
// v.WarningBudgetRemove(req.StockId)
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VoucherBiz) WarningSend(ctx context.Context, str string) error {
|
func (v *VoucherBiz) WarningSend(ctx context.Context, str string) error {
|
||||||
|
|
||||||
return v.DingMixRepo.SendMarkdownMessage(ctx, "券预算不足", str)
|
return v.DingMixRepo.SendMarkdownMessage(ctx, "券预算不足", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatAsCard(req *do.WarningBudget) string {
|
func formatAsCard(req *do.WarningBudget) string {
|
||||||
var card strings.Builder
|
var card strings.Builder
|
||||||
|
|
||||||
card.WriteString("### 🎫 " + req.StockName + "\n\n")
|
card.WriteString("### " + req.StockName + "\n\n")
|
||||||
|
|
||||||
// 基本信息
|
// 基本信息
|
||||||
card.WriteString("#### 💰 基本信息\n")
|
card.WriteString("#### 🎫 基本信息\n")
|
||||||
card.WriteString(fmt.Sprintf("- **批次号**: %s\n", req.StockId))
|
card.WriteString(fmt.Sprintf("- **批次号**: %s\n", req.StockId))
|
||||||
card.WriteString(fmt.Sprintf("- **活动号**: %s\n", req.StockNo))
|
card.WriteString(fmt.Sprintf("- **活动号**: %s\n", req.StockNo))
|
||||||
card.WriteString(fmt.Sprintf("- **面额**: %d元\n", req.Amount))
|
card.WriteString(fmt.Sprintf("- **面额**: %d元\n", req.Amount))
|
||||||
|
|
|
||||||
|
|
@ -117,11 +117,14 @@ func (c *TalkClient) SendLinkMessage(title, text, messageURL, picURL string, atM
|
||||||
|
|
||||||
// SendMarkdownMessage 发送 Markdown 消息并可 @ 人员
|
// SendMarkdownMessage 发送 Markdown 消息并可 @ 人员
|
||||||
func (c *TalkClient) SendMarkdownMessage(title, text string, atMobiles []string, isAtAll bool) error {
|
func (c *TalkClient) SendMarkdownMessage(title, text string, atMobiles []string, isAtAll bool) error {
|
||||||
|
|
||||||
|
if len(atMobiles) > 0 {
|
||||||
var atStr string
|
var atStr string
|
||||||
for _, mobile := range atMobiles {
|
for _, mobile := range atMobiles {
|
||||||
atStr += fmt.Sprintf("<font color='#003BFF'>@%s</font>", mobile)
|
atStr += fmt.Sprintf("<font color='#00008B'>@%s</font>", mobile)
|
||||||
|
}
|
||||||
|
text += fmt.Sprintf("\n请尽快处理@相关人员%s", atStr)
|
||||||
}
|
}
|
||||||
text += atStr
|
|
||||||
|
|
||||||
message := map[string]interface{}{
|
message := map[string]interface{}{
|
||||||
"msgtype": "markdown",
|
"msgtype": "markdown",
|
||||||
|
|
|
||||||
|
|
@ -142,14 +142,14 @@ func TestWarningBudgetText(t *testing.T) {
|
||||||
|
|
||||||
markdownTitle := "批次预算预警"
|
markdownTitle := "批次预算预警"
|
||||||
|
|
||||||
//atMobiles := []string{"18666173766"}
|
atMobiles := []string{"18666173766"}
|
||||||
|
|
||||||
webhookURL := "https://oapi.dingtalk.com/robot/send?access_token=5f10c2213cbf8168985cb2d061ebb1a5f70bd1dd47ec7cef58fa6fe545d52588"
|
webhookURL := "https://oapi.dingtalk.com/robot/send?access_token=5f10c2213cbf8168985cb2d061ebb1a5f70bd1dd47ec7cef58fa6fe545d52588"
|
||||||
secret := "SEC77b63d70a9e22317144e712b4538ce1e0013db885c65f7f9bae283e8958b39eb"
|
secret := "SEC77b63d70a9e22317144e712b4538ce1e0013db885c65f7f9bae283e8958b39eb"
|
||||||
|
|
||||||
client := NewDingTalkClient(webhookURL, secret)
|
client := NewDingTalkClient(webhookURL, secret)
|
||||||
|
|
||||||
if err := client.SendMarkdownMessage(markdownTitle, str, nil, false); err != nil {
|
if err := client.SendMarkdownMessage(markdownTitle, str, atMobiles, false); err != nil {
|
||||||
fmt.Println("Markdown 消息发送失败:", err)
|
fmt.Println("Markdown 消息发送失败:", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Markdown 消息发送成功")
|
fmt.Println("Markdown 消息发送成功")
|
||||||
|
|
@ -159,10 +159,10 @@ func TestWarningBudgetText(t *testing.T) {
|
||||||
func formatAsCard(req do.WarningBudget) string {
|
func formatAsCard(req do.WarningBudget) string {
|
||||||
var card strings.Builder
|
var card strings.Builder
|
||||||
|
|
||||||
card.WriteString("### 🎫 " + req.StockName + "\n\n")
|
card.WriteString("### " + req.StockName + "\n\n")
|
||||||
|
|
||||||
// 基本信息
|
// 基本信息
|
||||||
card.WriteString("#### 💰 基本信息\n")
|
card.WriteString("#### 🎫 基本信息\n")
|
||||||
card.WriteString(fmt.Sprintf("- **批次号**: %s\n", req.StockId))
|
card.WriteString(fmt.Sprintf("- **批次号**: %s\n", req.StockId))
|
||||||
card.WriteString(fmt.Sprintf("- **活动号**: %s\n", req.StockNo))
|
card.WriteString(fmt.Sprintf("- **活动号**: %s\n", req.StockNo))
|
||||||
card.WriteString(fmt.Sprintf("- **面额**: %d元\n", req.Amount))
|
card.WriteString(fmt.Sprintf("- **面额**: %d元\n", req.Amount))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue