package period_profit import ( "app/commons/core" "app/commons/model/entity" "app/commons/services" "app/commons/utils" "errors" "fmt" "github.com/shopspring/decimal" "gorm.io/gorm" ) type Service struct { //job *entity.SysJob services.CommonService } func NewService() *Service { return &Service{} } // 期任务 // nextPeriod 是否下一期 func (s *Service) RunPeriodProfit(nextPeriod bool) error { var err error // 期任务预创建 if err = s.PreCreationPeriods(); err != nil { return err } // 获取最近一期 运行中或完成任务 nextPeriodJob, err := s.getNextRunPeriodJob() if err != nil { return err } nowPeriodNo := utils.NowPeriodNo() // 正常运行当期任务 / 当前开启 nextPeriod 无视时间 运行下一期 if nextPeriodJob.PeriodNo == nowPeriodNo || nextPeriod { if err = s.DB().Model(&entity.StakePeriodJob{}). Where("id", nextPeriodJob.Id). Update("job_state", entity.PeriodJobStateRunning).Error; err != nil { return err } if err = s.runPeriodTask(nextPeriodJob.PeriodNo); err != nil { return err } } err = s.DisProfit() if err != nil { return err } return nil } func (s *Service) runPeriodTask(periodNo string) error { err := s.calCurrentStakeProfit(periodNo) if err != nil { return err } err = s.calLevelProfit(periodNo) if err != nil { return err } updateStm := s.DB().Model(&entity.StakePeriodJob{}). Where("period_no", periodNo). Where("job_state", entity.PeriodJobStateRunning). Updates(map[string]interface{}{ "level_profit_is_cal": true, "job_state": entity.PeriodJobStateSuccess, }) if updateStm.RowsAffected != 1 || updateStm.Error != nil { core.JobLog.Errorf("update fail RowsAffected:%d err:%+v", updateStm.RowsAffected, updateStm.Error) return err } return nil } func (s *Service) getNextRunPeriodJob() (*entity.StakePeriodJob, error) { firstWaiting, err := s.FirstStakePeriodJob(s.DB().Where("job_state = ?", entity.PeriodJobStateWaiting)) if err != nil { return nil, err } runningOrSuccessOrFailRow, err := s.FirstStakePeriodJob(s.DB().Where("job_state != ?", entity.PeriodJobStateWaiting)) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return firstWaiting, nil } return nil, err } if runningOrSuccessOrFailRow.JobState == entity.PeriodJobStateSuccess { return firstWaiting, nil } if runningOrSuccessOrFailRow.JobState == entity.PeriodJobStateRunning { return nil, fmt.Errorf("存在运行中期任务:%s", runningOrSuccessOrFailRow.PeriodNo) } if runningOrSuccessOrFailRow.JobState == entity.PeriodJobStateFailure { return nil, fmt.Errorf("存在运行错误期任务:%s,必须处理错误后才可以正常运行", runningOrSuccessOrFailRow.PeriodNo) } return nil, fmt.Errorf("期任务:%s,未知状态错误", runningOrSuccessOrFailRow.PeriodNo) } // 预创建3期任务 func (s *Service) PreCreationPeriods() error { var err error firstPeriodJob, err := s.FirstStakePeriodJob(s.DB().Where("job_state", entity.PeriodJobStateWaiting)) if err != nil { // 当无法占到时创建一条 if errors.Is(err, gorm.ErrRecordNotFound) { firstPeriodJob, err = s.newPeriods(utils.NowPeriodNo()) if err != nil { return err } } else { return err } } lastPeriodJob, err := s.LastStakePeriodJob(s.DB().Where("job_state", entity.PeriodJobStateWaiting)) if err != nil { return err } // 计算两期时间跨度 n := utils.CalPeriodNosSpan(firstPeriodJob.PeriodNo, lastPeriodJob.PeriodNo) // 保持三期创建 if n < 3 { // 目标期 targetPeriod, err := utils.JumpToPeriodNo(firstPeriodJob.PeriodNo, 3) if err != nil { return err } nowPeriod := lastPeriodJob.PeriodNo for { nextPeriod, err := utils.NextPeriodNo(nowPeriod) if err != nil { return err } if _, err = s.newPeriods(nextPeriod); err != nil { return err } if nextPeriod >= targetPeriod { break } nowPeriod = nextPeriod } } return err } // 创建期任务 func (s *Service) newPeriods(periodNo string) (*entity.StakePeriodJob, error) { newRow := &entity.StakePeriodJob{ PeriodNo: periodNo, JobState: entity.PeriodJobStateWaiting, StaticSymbolProfit: decimal.Zero, StaticUsdProfit: decimal.Zero, Desc: "", } err := s.DB().Create(&newRow).Error return newRow, err }