代码实现思路
- 使用
time.Ticker
来实现定时触发。time.Ticker
会按照设定的时间间隔向其 C
通道发送时间值。
- 在
Goroutine
中执行复杂业务逻辑,每次从 time.Ticker
的通道接收时间值时,执行一次业务逻辑。
- 为了优雅地停止定时任务,引入一个
context.Context
来管理 Goroutine
的生命周期。context.Context
可以用于通知 Goroutine
停止执行。
关键代码片段
package main
import (
"context"
"fmt"
"os"
"time"
)
// 模拟复杂业务逻辑
func complexBusinessLogic(ctx context.Context) error {
// 从数据库读取数据
// 处理数据
// 写入文件
file, err := os.OpenFile("output.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString("Data processed at " + time.Now().Format(time.RFC3339) + "\n")
if err != nil {
return err
}
return nil
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
go func() {
for {
select {
case <-ticker.C:
err := complexBusinessLogic(ctx)
if err != nil {
fmt.Println("Error in business logic:", err)
}
case <-ctx.Done():
return
}
}
}()
// 模拟程序运行一段时间后停止定时任务
time.Sleep(60 * time.Second)
cancel()
fmt.Println("定时任务已停止")
}
优雅停止定时任务的解释
- 创建
context.Context
:通过 context.WithCancel(context.Background())
创建一个可取消的 context.Context
。ctx
用于控制 Goroutine
的生命周期,cancel
函数用于取消 ctx
。
- 在
select
中监听 ctx.Done()
:在 Goroutine
内部的 select
语句中,除了监听 ticker.C
通道外,还监听 ctx.Done()
通道。当 ctx.Done()
通道接收到信号时,意味着 context.Context
被取消,此时 Goroutine
应该停止执行,通过 return
语句退出 Goroutine
。
- 调用
cancel
函数:在需要停止定时任务的地方,调用 cancel
函数,这会向 ctx.Done()
通道发送信号,通知 Goroutine
停止执行,从而实现优雅停止定时任务。同时,time.Ticker
也通过 defer ticker.Stop()
停止,避免资源泄漏。