time.AfterFunc 定时器函数如何避免程序重启造成的中断

time.AfterFunc 定时器如何避免程序重启造成的中断
线上不可避免的会重启进程, 一重启这个定时器就没了, 应该有啥解决办法的吧, 不然这个函数 作用就不太高了

阅读 6.4k
3 个回答

定时器的话 推荐用 github.com/robfig/cron 应该可以满足你的需求。

认可 @xiaowei520 的思路。

首先,time.AfterFunc 只是个简单的函数,多长时间执行某个动作这个设定只对当前进程有效,如果异常退出,需要一些恢复机制恢复。而关于如何恢复,这应该是程序员考虑的问题。

为实现恢复,肯定需要将保留现场。可行的方案就是把任务配置到外部存储中,保存任务信息,比如任务标识,执行时间,执行任务类型,状态等等。存储到哪里呢?可以是 xiaowei520 说的 redis,或者 MySQL 也行,当然,如果你有精力的话,也可以自己设计个文件结构来保存任务信息。

这种方式的缺点是,如果任务数比较多,一次加载进来会有性能影响,需要考虑负载均衡。而且,任务都加载在一个进程中容灾能力也不是很好,因为只有一个运行中的程序在处理任务,挂了就不行了。

对于上面说的问题,可以尝试引入一些外部服务,比如带有定时功能的 MQ。这样的话,容错的事情就交给 MQ 实现了。通常很多 MQ 组件都是高可用的,可以配置集群。然后,只要向队列上添加多个 consumer,即可实现负载均衡的效果,如果其中某台机器挂了,还有其他的 consumer 在运行,实现容灾能力。

我在网上找到了 RabbitMQ 实现定时消息的文章,如果有需要,可以看看能否参考一下。[Rabbitmq延迟队列实现定时任务](https://blog.csdn.net/wantnru...

新手上路,请多包涵

可以使用https://github.com/DanPlayer/...来解决这个问题

type User struct {
    Name string
    Age  int
}

// check for exception shutdown and restart watch task
    err = watch.StartWithCheckRestart(func(c timewatch.Watch) {
        fmt.Println(c)
        infoMap := c.CustomizedAttributes.(map[string]interface{})
        marshal, _ := json.Marshal(infoMap)
        var info User
        _ = json.Unmarshal(marshal, &info)

        fmt.Println(fmt.Sprintf("User struct name: %s", info.Name))
        fmt.Println(fmt.Sprintf("User struct age: %d", info.Age))
        fmt.Println("do that u want")
    })
    if err != nil {
        fmt.Println(err)
    }

    var watch = timewatch.Service(timewatch.Options{
        Key: "MsgWatch",
        Cache: cache.NewRedis(cache.RedisOptions{
            Addr:     "127.0.0.1:6379",
            Password: "",
            DB:       0,
        }),
        OutTimeAct: true,
    })

    // watch plan add
    timer, err := watch.AfterFunc(5*time.Second, timewatch.Watch{
        Field: "TestField",
        CustomizedAttributes: User{
            Name: "Dan",
            Age:  20,
        }, // could use some self make that u want set attributes in watch.CheckRestart
    }, func() {
        fmt.Println("plan to func")
    })
    if err != nil {
        fmt.Println(err)
        return
    }
推荐问题
宣传栏