【问题标题】:Prometheus go client error context deadline exceededPrometheus go 客户端错误上下文截止日期已超出
【发布时间】:2020-11-10 10:09:51
【问题描述】:

我有一个 Prometheus 服务器,其数据库包含一些指标。我需要一个从数据库中获取这些指标并每分钟循环发送到另一台服务器的进程。我从 Prometheus 示例中编写了以下代码:

client, err := api.NewClient(api.Config{Address: "http://localhost:9090",})
if err != nil {
    log.Error(err)
    os.Exit(1)
}

v1api := v1.NewAPI(client)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

for { //main loop
    if result, warnings, err := v1api.Query(ctx, "patroni_patroni_info", time.Now().Add(-1 * time.Minute)); err != nil {
        log.Error(err)
    } else {
        if len(warnings) > 0 {
            log.Warning(warnings)
        }
        if err = sendMetricToAnotherServer(result); err != nil {
            log.Error(err)
        }
    }
    log.Debugf("main sleeping %ds...", opts.ServersRefreshLoopSeconds)
    time.Sleep(time.Second * time.Duration(opts.ServersRefreshLoopSeconds))
}

现在第一次发送工作正常,但从第二次发送开始出现以下错误。

2020/11/10 09:56:36 ERROR main: Post http://localhost:9090/api/v1/query: context deadline exceeded

我认为原因是传递给查询 API 的上下文的截止日期已过期。解决问题的办法就是在循环中简单地移动以下两行:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

我验证它有效,现在它能够每分钟发送一次指标,但我不确定这个修复程序是否能长期正常工作。我担心取消功能应该以不同的方式管理以正确释放资源,最终不必在每个循环中创建上下文,而只需延长截止日期。

有谁知道我可以正确修复我的代码以避免可能的内存泄漏或其他潜在的未来问题?

【问题讨论】:

  • 是的,我理解这一点,正如我在消息中所说的那样。但我不知道如何正确管理取消操作。此外,每次调用 context.WithTimeout 都会创建一个 10 秒生命的新上下文。在一个循环中,这会创建很多对象,有没有办法重用相同的上下文并简单地延长 1 分钟的期限?我看到了 API,但即使 WithDeadline 也会创建上下文的副本。

标签: go prometheus


【解决方案1】:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

这个上下文总共被所有请求使用了 10 秒;你应该把它移到 for 循环中,这样每个请求都可以有 10 秒的上下文。

理想情况下,您不希望此延迟继续堆叠;所以你可以

  1. 将其移动到另一个函数(或创建一个内联函数并调用它)这样可以确保每次都调用 defer 函数并且不会堆叠。
  2. 在循环结束时手动调用取消函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 2020-04-28
    • 2017-07-07
    相关资源
    最近更新 更多