Files
2026-09-11 01:41:52 +08:00

122 lines
4.3 KiB
Go

package mysqldao
import (
"context"
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/global"
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/mysqlmodel"
"gorm.io/gorm"
)
// BenefitGrantTaskDao 权益发放补偿任务数据访问
type BenefitGrantTaskDao struct {
db *gorm.DB
}
// NewBenefitGrantTaskDao 创建补偿任务 DAO
func NewBenefitGrantTaskDao() *BenefitGrantTaskDao {
return &BenefitGrantTaskDao{db: global.MysqlEngine}
}
// BenefitGrantTaskCreate 创建补偿任务,依赖唯一索引 (order_no, benefit_type) 防重复发放。
func (d *BenefitGrantTaskDao) BenefitGrantTaskCreate(ctx context.Context, task *mysqlmodel.BenefitGrantTask) error {
ctx, span := global.Tracer.Start(ctx, "mysqldao.BenefitGrantTaskCreate")
defer span.End()
if err := d.db.WithContext(ctx).Create(task).Error; err != nil {
span.RecordError(err)
return err
}
return nil
}
// BenefitGrantTaskGetByOrderNoAndType 按订单号+权益类型查询补偿任务。
func (d *BenefitGrantTaskDao) BenefitGrantTaskGetByOrderNoAndType(ctx context.Context, orderNo string, benefitType int8) (*mysqlmodel.BenefitGrantTask, error) {
ctx, span := global.Tracer.Start(ctx, "mysqldao.BenefitGrantTaskGetByOrderNoAndType")
defer span.End()
var task mysqlmodel.BenefitGrantTask
if err := d.db.WithContext(ctx).
Where("order_no = ? AND benefit_type = ?", orderNo, benefitType).
First(&task).Error; err != nil {
span.RecordError(err)
return nil, err
}
return &task, nil
}
// BenefitGrantTaskUpdateByID 按主键更新补偿任务字段。
func (d *BenefitGrantTaskDao) BenefitGrantTaskUpdateByID(ctx context.Context, id int64, updates map[string]any) error {
ctx, span := global.Tracer.Start(ctx, "mysqldao.BenefitGrantTaskUpdateByID")
defer span.End()
if err := d.db.WithContext(ctx).Model(&mysqlmodel.BenefitGrantTask{}).Where("id = ?", id).Updates(updates).Error; err != nil {
span.RecordError(err)
return err
}
return nil
}
// BenefitGrantTaskListPending 查询待发放的补偿任务(status=0),按主键升序。
func (d *BenefitGrantTaskDao) BenefitGrantTaskListPending(ctx context.Context, limit int) ([]mysqlmodel.BenefitGrantTask, error) {
ctx, span := global.Tracer.Start(ctx, "mysqldao.BenefitGrantTaskListPending")
defer span.End()
var list []mysqlmodel.BenefitGrantTask
if err := d.db.WithContext(ctx).
Where("status = ?", 0).
Order("id ASC").
Limit(limit).
Find(&list).Error; err != nil {
span.RecordError(err)
return nil, err
}
return list, nil
}
// BenefitGrantTaskReset 将失败任务重置为待发放(首次发放遇到 failed 记录时复用)。
// 保留 retry_count:不归零,保证重试上限与人工介入机制不被重置绕过;
// 调用方应配合冷却期使用,避免高频回调无限重置。
func (d *BenefitGrantTaskDao) BenefitGrantTaskReset(ctx context.Context, id int64) error {
ctx, span := global.Tracer.Start(ctx, "mysqldao.BenefitGrantTaskReset")
defer span.End()
if err := d.db.WithContext(ctx).Model(&mysqlmodel.BenefitGrantTask{}).
Where("id = ?", id).
Updates(map[string]any{"status": 0, "last_error": ""}).Error; err != nil {
span.RecordError(err)
return err
}
return nil
}
// BenefitGrantTaskClaim 条件认领任务(待发放/失败 -> 发放中),返回是否认领成功,防并发重复发放。
func (d *BenefitGrantTaskDao) BenefitGrantTaskClaim(ctx context.Context, id int64) (bool, error) {
ctx, span := global.Tracer.Start(ctx, "mysqldao.BenefitGrantTaskClaim")
defer span.End()
res := d.db.WithContext(ctx).Model(&mysqlmodel.BenefitGrantTask{}).
Where("id = ? AND status IN (?, ?)", id, 0, 2).
Update("status", 3)
if res.Error != nil {
span.RecordError(res.Error)
return false, res.Error
}
return res.RowsAffected > 0, nil
}
// BenefitGrantTaskRecoverStale 将「发放中」且超过一定时间未完成的任务重置为待发放(认领后崩溃的恢复)。
func (d *BenefitGrantTaskDao) BenefitGrantTaskRecoverStale(ctx context.Context, beforeUpdatedAt int64) (int64, error) {
ctx, span := global.Tracer.Start(ctx, "mysqldao.BenefitGrantTaskRecoverStale")
defer span.End()
res := d.db.WithContext(ctx).Model(&mysqlmodel.BenefitGrantTask{}).
Where("status = ? AND updated_at < ?", 3, beforeUpdatedAt).
Update("status", 0)
if res.Error != nil {
span.RecordError(res.Error)
return 0, res.Error
}
return res.RowsAffected, nil
}