voucher/internal/biz/cron_notice.go

186 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package biz
import (
"context"
"errors"
"fmt"
"github.com/go-kratos/kratos/v2/log"
"github.com/redis/go-redis/v9"
"golang.org/x/sync/errgroup"
"time"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
"voucher/internal/pkg/lock"
)
func (v *VoucherBiz) Notice(ctx context.Context) error {
if err := v.isCanNotice(ctx); err != nil {
return err
}
now := time.Now()
// 获取 NoticeStartDays 天前的日期
noticeStartDay := now.AddDate(0, 0, int(-v.bc.Cmb.NoticeStartDays))
// 获取 NoticeStartDays 天前 00:00:00 的时间
startTime := time.Date(noticeStartDay.Year(), noticeStartDay.Month(), noticeStartDay.Day(), 0, 0, 0, 0, noticeStartDay.Location())
// 获取 NoticeEndDays 天前的日期
noticeEndDay := now.AddDate(0, 0, int(-v.bc.Cmb.NoticeEndDays))
// 获取 NoticeEndDays 天 23:59:59 的时间
endTime := time.Date(noticeEndDay.Year(), noticeEndDay.Month(), noticeEndDay.Day(), 23, 59, 59, 0, noticeEndDay.Location())
return v.timeSliceQuery(ctx, startTime, endTime)
}
func (v *VoucherBiz) timeSliceQuery(ctx context.Context, startTime, endTime time.Time) error {
duration := 1 * time.Hour
eg := new(errgroup.Group)
eg.SetLimit(5)
for start := startTime; start.Before(endTime); start = start.Add(duration) {
end := start.Add(duration) // 计算每次请求的结束时间
if end.After(endTime) {
end = endTime
}
req := &bo.FindInBatchesUseBo{
StartTime: &start,
EndTime: &end,
}
eg.Go(func() error {
return v.ExecuteNotice(ctx, req)
})
}
return eg.Wait() // 仅返回第一个错误
}
func (v *VoucherBiz) ExecuteNotice(ctx context.Context, req *bo.FindInBatchesUseBo) error {
log.Warnf("订单定时通知:%+v", req)
return v.OrderRepo.FindInBatches(ctx, req, func(ctx context.Context, rows []*bo.OrderBo) error {
for _, order := range rows {
if err := v.notice(ctx, order); err != nil {
log.Errorf("招行查询券订单状态发生错误,orderNo:%s,err:%v", order.OrderNo, err)
}
}
return nil
})
}
func (v *VoucherBiz) isCanNotice(ctx context.Context) error {
if v.bc.Cmb.NoticeStartDays == 0 {
return errors.New("noticeStartDays eq 0")
}
if v.bc.Cmb.NoticeEndDays == 0 {
return errors.New("noticeEndDays eq 0")
}
cache := vo.CmbBatchNoticeCacheKey.BuildCache([]string{""})
_, err := v.rdb.Rdb.Get(ctx, cache.Key).Result()
if err == nil {
return fmt.Errorf("notice 获取redis缓存存在已被执行,本台服务不做执行")
}
if err != redis.Nil {
return fmt.Errorf(fmt.Sprintf("notice 获取redis缓存%s异常:%v", cache.Key, err))
}
c := vo.CmbBatchNoticeLockKey.BuildCache([]string{""})
return lock.NewMutex(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error {
// 二次获取,判定处理,以免获取锁后又执行了一次
cacheValue, err2 := v.rdb.Rdb.Get(ctx, cache.Key).Result()
if err2 != nil && err2 != redis.Nil {
return fmt.Errorf(fmt.Sprintf("notice 二次获取redis缓存%s异常:%v", cache.Key, err2))
}
if len(cacheValue) > 0 {
return fmt.Errorf("notice 二次获取redis缓存存在已被执行,本台服务不做执行")
}
if err = v.rdb.Rdb.Set(ctx, cache.Key, fmt.Sprintf("%d_%d", v.bc.Cmb.NoticeStartDays, v.bc.Cmb.NoticeEndDays), c.TTL).Err(); err != nil {
return fmt.Errorf(fmt.Sprintf("notice 设置redis缓存%s异常:%v", cache.Key, err))
}
log.Warnf("notice 获取redis缓存,不存在,开始处理")
return nil
})
}
func (v *VoucherBiz) notice(ctx context.Context, order *bo.OrderBo) error {
// 批量通知不做数据存储,量会很大
status, err := v.WechatCpnRepo.Query(ctx, order)
if err != nil {
return err
}
if order.Status == status {
//log.Warnf("notice 券状态未改变:%s忽略不处理,orderNo:%s", order.Status.GetText(), order.OrderNo)
return nil
}
event, err := status.GetOrderNotifyEvent()
if err != nil {
return err
}
orderNotify := &bo.OrderNotifyBo{
OrderNo: order.OrderNo,
NotifyUrl: order.NotifyUrl,
Channel: order.Channel,
Event: event,
Type: order.Type,
}
if err = v.cmbNotice(ctx, order, orderNotify); err != nil {
return err
}
return v.UpdateOrderStatus(ctx, order.ID, status)
}
func (v *VoucherBiz) cmbNotice(ctx context.Context, order *bo.OrderBo, orderNotify *bo.OrderNotifyBo) error {
if !orderNotify.Event.CanNotify() {
//log.Warnf("notice 券状态:%s忽略不通知,orderNo:%s", orderNotify.Event.GetText(), order.OrderNo)
return nil
}
request, err := v.Cmb.NotifyRequest(ctx, order, orderNotify)
if err != nil {
return err
}
reply, err := v.CmbMixRepo.Request(ctx, request, order.NotifyUrl)
if err != nil {
return fmt.Errorf("orderNo:%s,outBizNo:%s,%s", order.OrderNo, order.OutBizNo, err.Error())
}
if reply.RespCode != vo.CmbResponseStatusSuccess.GetValue() {
return errors.New(reply.RespMsg)
}
return nil
}