prometheus的sdk client_golang 使用 定时器

发布时间 2023-08-08 12:08:18作者: 腐汝

之前线上监控的agent都是直接  time.Sleep(time.Duration(collectInterval) * time.Second) ,多少有些许的low,每次开始采集数据的时间都是从程序开始执行就开始采集,很显然这种偷懒的方式是不合理的。

1、简单复制粘贴一下

func AbNormalLoglistener(collectInterval int)  {
    abnormal_loglistener_Gauge := prometheus.NewGaugeVec(
        prometheus.GaugeOpts{
            Namespace: "tc",
            Subsystem: "serverMetricExtend",
            Name:      "abnormal_loglistener_log",
            Help:      "Loglistener An exception exists in the log file.",
        },
        []string{
            "hostname",
            "alert_name",
        },
    )
    prometheus.MustRegister(abnormal_loglistener_Gauge)

    _t := tools.Server{}
    sname := _t.GetServerHostName()

    go func() {
        defer func() {
            if r := recover(); r != nil {
                metricLog.Error(r)
            }
        }()

        ticker := time.NewTicker(time.Duration(collectInterval) * time.Second)
        now := time.Now()
        nextMinute := now.Truncate(time.Duration(collectInterval) * time.Second).Add(time.Duration(collectInterval) * time.Second)
        waitTime := nextMinute.Sub(now)
        time.Sleep(waitTime)

        for {
            metricsBack := _t.FetchDirModTime()
            for alert_name, status := range metricsBack{
                abnormal_loglistener_Gauge.With(prometheus.Labels{"hostname": sname, "alert_name": alert_name}).Set(float64(status))
            }

            <-ticker.C
            nextMinute = nextMinute.Add(time.Duration(collectInterval) * time.Second)
            waitTime = nextMinute.Sub(time.Now())
            time.Sleep(waitTime)

        }
    }()
}

2、方式一 time.Ticker

package main

import (
    "fmt"
    "time"
)

func main() {
    // 创建一个定时器,每隔一分钟触发一次
    ticker := time.NewTicker(time.Minute)

    // 获取当前时间
    now := time.Now()

    // 计算下一分钟的开始时间
    nextMinute := now.Truncate(time.Minute).Add(time.Minute)

    // 计算需要等待的时间
    waitTime := nextMinute.Sub(now)

    // 等待到下一分钟的开始时间
    time.Sleep(waitTime)

    // 使用一个无限循环来控制方法的执行
    for {
        // 执行你的方法
        fmt.Println("执行方法")

        // 等待定时器的下一次触发事件
        <-ticker.C

        // 计算下一分钟的开始时间
        nextMinute = nextMinute.Add(time.Minute)

        // 计算需要等待的时间
        waitTime = nextMinute.Sub(time.Now())

        // 等待到下一分钟的开始时间
        time.Sleep(waitTime)
    }
}

 

3、方式二 time.Timer

package main

import (
    "fmt"
    "time"
)

func main() {
    // 获取当前时间
    now := time.Now()

    // 计算下一分钟的开始时间
    nextMinute := now.Truncate(time.Minute).Add(time.Minute)

    // 计算需要等待的时间
    waitTime := nextMinute.Sub(now)

    // 创建一个定时器,在等待时间结束后执行任务
    timer := time.NewTimer(waitTime)

    // 使用一个无限循环来控制协程的执行
    for {
        <-timer.C // 等待定时器的触发事件

        // 执行你的协程任务
        go func() {
            fmt.Println("执行协程任务")
            // 在这里编写你的协程任务逻辑
        }()

        // 计算下一分钟的开始时间
        nextMinute = nextMinute.Add(time.Minute)

        // 重新计算需要等待的时间
        waitTime = nextMinute.Sub(time.Now())

        // 重置定时器
        timer.Reset(waitTime)
    }
}

 

4、这两种方式的区别,gpt给的答案,请各位自行斟酌

  1. time.NewTimer

    • time.NewTimer 创建一个单次触发的定时器,它在指定的时间间隔过后触发一次。
    • 适用于需要在指定时间间隔后执行一次操作的场景。
    • 可以使用 timer.Reset 方法重新设置定时器的触发时间。
  2. time.NewTicker

    • time.NewTicker 创建一个重复触发的定时器,它会以固定的时间间隔重复触发。
    • 适用于需要定期执行某个操作的场景,比如每隔一段时间执行一次任务。
    • 每次触发时,time.Ticker 类型的值会发送一个时间到其内部的通道 C,你可以使用 <-ticker.C 来等待触发事件。
    • 可以使用 ticker.Stop 方法停止定时器的触发。

 

5、一些点的解惑

m := time.Now().Truncate(time.Minute)
fmt.Printf("m:%s\n",m )

s := time.Now().Truncate(time.Duration(3600) * time.Second)
fmt.Printf("s:%s\n",s )

执行返回结果,自行感受,time.Now().Truncate():

m:2023-08-08 11:56:00 +0800 CST
s:2023-08-08 11:00:00 +0800 CST

 

6、文章仅个人记录,要想深入请自行分析源码。