Golang 实现每天定时任务
在 Go 中实现每天定时任务有几种常用方法,以下是详细的实现方案:
1. 使用 time.Ticker
+ 时间判断(简单场景)
package main
import (
"fmt"
"time"
)
func main() {
ticker := time.NewTicker(1 * time.Minute) // 每分钟检查一次
defer ticker.Stop()
for now := range ticker.C {
if isTargetTime(now) { // 判断是否是目标时间
fmt.Println("执行每日任务:", now.Format("2006-01-02 15:04:05"))
dailyTask()
}
}
}
// 判断当前时间是否为目标执行时间(例如每天凌晨2点)
func isTargetTime(t time.Time) bool {
return t.Hour() == 2 && t.Minute() == 0
}
func dailyTask() {
fmt.Println("正在执行每日任务...")
// 这里放置你的实际业务逻辑
}
2. 使用 github.com/robfig/cron
(推荐)
安装 cron v3:
go get github.com/robfig/cron/v3@v3.0.0
示例代码:
package main
import (
"fmt"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
// 添加每日任务(每天凌晨2点30分执行)
id, err := c.AddFunc("30 2 * * *", func() {
fmt.Println("Cron触发每日任务")
dailyTask()
})
if err != nil {
fmt.Printf("添加定时任务失败: %v\n", err)
return
}
fmt.Printf("已添加定时任务,ID: %d\n", id)
c.Start()
defer c.Stop()
// 保持程序运行
select {}
}
func dailyTask() {
fmt.Println("正在执行每日任务...")
}
Cron表达式说明:
* * * * *
- - - - -
| | | | |
| | | | 星期几 (0 - 6) (周日=0)
| | | 月份 (1 - 12)
| | 日 (1 - 31)
| 小时 (0 -23)
分钟 (0 -59)
示例:
"30 2 * * *" = 每天凌晨2点30分
"0 */6 * * *" =每6小时整点执行一次
3. gocron
库(更友好的API)
安装:
go get github.com/go-co-op/gocron@v1.18.0
示例代码:
package main
import (
"fmt"
"time"
"github.com/go-co-op/gocron"
)
func main() {
s := gocron.NewScheduler(time.Local)
// UTC+8时区,每天早上9点15分执行
_, err := s.Every(1).Day().At("09:15").Do(dailyTask)
if err != nil {
panic(err)
}
s.StartAsync()
defer s.Stop()
select {}
}
func dailyTask() {
fmt.Printf("%s: Executing daily task\n", time.Now().Format(time.RFC3339))
}
4. context控制的任务管理
package main
import (
"context"
"fmt"
"os/signal"
"syscall"
"time"
"github.com/robfig/cron/v3"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
c := cron.New(cron.WithLocation(time.Local)) //使用本地时区
_, err := c.AddFunc("@daily", func(){
fmt.Printf("[%s] Daily job started\n", time.Now().Format(time.DateTime))
doDailyJob(ctx)
fmt.Printf("[%s] Daily job completed\n", time.Now().Format(time.DateTime))
})
if err != nil{
panic(err)
}
c.Start()
<-ctx.Done()
fmt.Println("\nReceived shutdown signal...")
ctxShutdown, cancel := context.WithTimeout(context.Background(),5*time.Second)
defer cancel()
<-c.Stop().Done()
fmt.Println("Cron jobs stopped cleanly")
}
func doDailyJob(ctx context.Context){
select{
case <-ctx.Done():
return
default:
fmt.Println("- Processing dayly data...")
time.Sleep(3*time.Second)//模拟耗时操作
}
}
最佳实践建议
1.时区处理:明确指定时区,避免服务器时区设置导致的时间偏差问题。
2.错误恢复:在定时任务的函数中添加recover机制,防止panic导致整个调度停止。
3.日志记录:详细记录每次任务的开始、结束时间和状态。
4.分布式锁:如果是多实例部署,考虑使用Redis等实现分布式锁,避免重复执行。
5.资源清理:确保在程序退出前正确关闭所有定时器或调度器。
内容由零声教学AI助手提供,问题来源于学员提问