Last active
July 2, 2025 06:27
-
-
Save garenchan/c9f4061b4c97403f188dfc31ada041ff to your computer and use it in GitHub Desktop.
github.com/robfig/cron/v3 定时任务串行,并尽可能保证间隔interval执行
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// delayIfStillRunning 让定时任务串行执行,上一次执行完毕后,至少等待interval后才会执行下一次 | |
func (m *Monitor) delayIfStillRunning() cron.JobWrapper { | |
return func(j cron.Job) cron.Job { | |
// 保证任务的串行执行 | |
var mu sync.RWMutex | |
// cron会每隔interval创建一个goroutine来执行定时任务,如果简单使用mu | |
// 来保证串行执行,并且当任务耗时比较严重时,会导致大量goroutine堆积在mu.Lock()上, | |
// 随着服务长时间运行,可能出现goroutine耗尽,最终导致程序崩溃。事实上,只需要有一个goroutine等待上一次任务结束 | |
var hasWaiter bool | |
var waiterMu sync.Mutex | |
return cron.FuncJob(func() { | |
waiterMu.Lock() | |
if hasWaiter { | |
waiterMu.Unlock() | |
return | |
} | |
hasWaiter = true | |
waiterMu.Unlock() | |
start := time.Now() | |
// log.Logger.Debug().Msgf("[cron][%+v][%s] start to wait lock.", j, start.String()) | |
mu.Lock() | |
defer mu.Unlock() | |
if dur := time.Since(start); dur > 3*time.Second { | |
log.Logger.Warn().Msgf("[cron][%+v][%s] The interval time may be set too short.", j, start.String()) | |
select { | |
case <-m.ctx.Done(): | |
return | |
case <-time.After(time.Duration(m.interval) * time.Second): | |
} | |
} | |
waiterMu.Lock() | |
hasWaiter = false | |
waiterMu.Unlock() | |
// log.Logger.Debug().Msgf("[cron][%+v][%s] start to run cron.", j, start.String()) | |
j.Run() | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment