go中定时任务

功能需求:定时查询库中已确认的行程,如果当前时间距离出发时间已有5小时就修改其状态为已完成;

本示例服务发布后会指定当天20:00第一次执行,如果20点后发布服务那就根据当前时间往后推5分钟。执行业务逻辑代码如果出错,就在设定的时间段中随机加个下次执行的时间。若重复执行成功后那么下次任务开始则是10小时后。详细请看代码:

func ScheduleTask() {
	// 首先计算离今天指定时间点最近的下一个时间点
	now := time.Now()
	//time.Date()创建一个指定日期 20点00分第一次执行
	targetTime := time.Date(now.Year(), now.Month(), now.Day(), 20, 0, 0, 0, time.Local)
	if targetTime.Before(now) {
		// 如果指定时间点晚于当前时间,则计算下一个指定时间点 5分钟后再执行
		//targetTime = targetTime.Add(10 * time.Hour)
		targetTime = targetTime.Add(5 * time.Minute)
	}
	fmt.Println("任务将在指定时间执行:", targetTime)

	// 根据设定的时间点启动定时器
	duration := targetTime.Sub(now)
	fmt.Println("距离下次指定时间点的时间间隔为:", duration)
	timer := time.NewTimer(duration)
	go func() {
		for {
			<-timer.C // 等待定时器事件
			// 这里编写需要执行的定时任务代码
			if err := func() error {
				defer func() {
					if err := recover(); err != nil {
						log.E().Msgf("执行定时任务出错:%v", err)
					}
				}()
				fmt.Println("定时任务执行了...")
				err := dao.ScheduleTaskCode()
				if err != nil {
					err = retry(func() error {
						return dao.ScheduleTaskCode()
					}, 5)
					if err != nil {
						log.E().Msgf("重复执行定时任务出错,并已达到最大次数:%v", err)
					}
				}
				// 重设定时器,以便下次能够正确触发
				targetTime = targetTime.Add(4 * time.Hour)
				//targetTime = targetTime.Add(1 * time.Minute)
				duration = targetTime.Sub(time.Now())
				fmt.Println("任务将在指定时间执行:", targetTime)
				fmt.Println("距离下次指定时间点的时间间隔为:", duration)
				timer.Reset(duration)
				return err
			}(); err != nil {
				log.E().Msgf("执行定时任务出错:%v", err)
			}
		}
	}()
}

// 需要执行的定时任务代码
func (d *Dao) ScheduleTaskCode() error {
	trips := []model.Trip{}
	err := d.pg.Where("trip_status = ?", "1").Find(&trips).Error
	if err != nil {
		return err
	}
	ids := []int64{}
	if len(trips) > 0 {
		for _, trip := range trips {
			//筛选出发5小时后的行程
			after5 := trip.TripTime + 18000
			if xtime.Now() >= after5 {
				ids = append(ids, trip.ID)
			}
		}
	}
	if len(ids) > 0 {
		//修改行程状态
		err = d.pg.Table("trips").Where("id IN ?", ids).Updates(map[string]interface{}{"trip_status": tripStatus}).Error
		if err != nil {
			return err
		}
		//修改同行状态
		err = d.pg.Table("trip_applications").Where("trip_id IN ? AND trip_status <> ?", ids, tripApplicationStatus).Updates(map[string]interface{}{"trip_status": tripStatus}).Error
		if err != nil {
			return err
		}
	}
	return err
}

func retry(fn func() error, times int) error {
	min := 5 * time.Second
	max := 1 * time.Minute
	bo := backoff.New(
		backoff.WithMinDuration(min),
		backoff.WithMaxDuration(max),
		backoff.WithFactor(2))
	//执行任务失败,使用Backoff确定下一次任务之前的等待时间

	var err error
	for i := 0; i < times; i++ {
		sleepDuration := bo.Duration()
		fmt.Printf("任务执行失败,将在%v后重试,已经执行了%v次。\n", sleepDuration, bo.Attempt())
		//睡眠指定时间
		time.Sleep(sleepDuration)
		if err = fn(); err != nil {
			return err
		}
		time.Sleep(1 * time.Second)
	}
	//重置Backoff对象
	bo.Reset()
	return err
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值