• golang定时器使用踩的坑:定时器每天执行一次


    golang定时器使用踩的坑

    项目背景以及问题

    项目中有这样一个需求,需要用定时器在每天的上午10:00:00处理某些业务逻辑,但是遇到了2个问题。
    不比比,上代码

    go func() {
    		for {
    			now := time.Now()
    			var next time.Time
    
    			//每天10:00与苏轼论道
    			if now.Hour() < 10 || now.Hour() == 10 {
    				next = now
    			} else {
    				next = now.Add(time.Hour * 24)
    			}
    
    			//每天10:00与苏轼论道
    			next = time.Date(next.Year(), next.Month(), next.Day(), 10, 0, 0, 0, next.Location())
    
    			// 定时时间已过,防止项目重启时,再次触发定时器。如10点执行一次,10:10重启了服务,此时设置为下一天执行
    
    			logger.Info("UpdateOndutys Now=%s Next=%s", now, next)
    			timer := time.NewTimer(next.Sub(now))
    
    			select {
    			case ts := <-timer.C:
    				// go function() //业务逻辑
    				logger.Info("Start UpdateOnduty_7day ts=%s", ts.String())
    				time.Sleep(120 * time.Second)
    				timer.Stop()
    			}
    		}
    	}()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    问题1:golang定时器有一个特点就是你设置一个过期的时间它仍然会执行,比如,当前是上午10:00:00,然后我设置定时器是今天的9:00:00去执行,它仍然会执行。
    问题2:如果定时器是上午10:00:00执行,然后我10:44:44重启了项目,然后它就又执行一次,但是需求是一天只执行一次。

    解决方案

    在我们启动定时器之前判断一下当前时间与定时器的执行时间大小,如果当前时间大于定时器执行时间,说明定时器已经执行过,那么就设置为明天再执行。如果当前时间小于定时器时间那么定时器未执行过,按照正常逻辑今日执行。

    go func() {
    		for {
    			now := time.Now()
    			var next time.Time
    
    			//每天10:00与苏轼论道
    			if now.Hour() < 10 || now.Hour() == 10 {
    				next = now
    			} else {
    				next = now.Add(time.Hour * 24)
    			}
    
    			//每天10:00与苏轼论道
    			next = time.Date(next.Year(), next.Month(), next.Day(), 10, 0, 0, 0, next.Location())
    
    			// 定时时间已过,防止项目重启时,再次触发定时器。如10点执行一次,10:10重启了服务,此时设置为下一天执行
    			if now.Unix() > next.Unix() {
    				next = now.Add(time.Hour * 24)
    				next = time.Date(next.Year(), next.Month(), next.Day(), 10, 0, 0, 0, next.Location())
    			}
    
    			logger.Info("UpdateOndutys Now=%s Next=%s", now, next)
    			timer := time.NewTimer(next.Sub(now))
    
    			select {
    			case ts := <-timer.C:
    				// go function() //业务逻辑
    				logger.Info("Start UpdateOnduty_7day ts=%s", ts.String())
    				time.Sleep(120 * time.Second)
    				timer.Stop()
    			}
    		}
    	}()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    【重拾C语言】四、循环程序设计典例整理(最大公因数、阶乘求和、正整数翻译、打印字符方阵、斐波那契数列……)
    JobManager 内存简介
    Android提供了多种方式来打开特定文件夹中的视频
    网安学习笔记-day14,nmap和hydra常用命令
    第6章 Mybatis高级查询(详解篇)
    当保存参数使用结构体时必备的开发技巧方式
    这波水文章
    ubuntu提高 github下载速度
    航天环宇提交招股书上会稿:计划募资6亿元,控股股东为李完小
    聊一聊 Valgrind 监视非托管内存泄露和崩溃
  • 原文地址:https://blog.csdn.net/java_xxxx/article/details/125543570