【发布时间】: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