#go #prometheus
#Вперед #prometheus
Вопрос:
У меня есть сервер 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()
Я проверил, что он работает, и теперь он может отправлять показатели каждую минуту, но я не уверен, что это исправление работает должным образом в долгосрочной перспективе. Я боюсь, что функцией отмены следует управлять по-другому, чтобы правильно освобождать ресурсы, и в конечном итоге нет необходимости создавать контекст в каждом цикле, а просто увеличивать крайний срок.
Кто-нибудь знает, что я могу правильно исправить свой код, чтобы избежать возможной утечки памяти или других потенциальных будущих проблем?
Комментарии:
1. Да, я понимаю это так, как сказано в моем сообщении. Но я не знаю, как правильно управлять операцией отмены. Кроме того, вызывайте контекст каждый раз. withTimeout создаст новый контекст на 10 секунд жизни. В цикле это создаст много объектов, есть ли способ повторно использовать тот же контекст и просто увеличить срок до 1 минуты? Я вижу API, но даже с помощью заголовка создается копия контекста.
Ответ №1:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
Этот контекст в общей сложности составляет 10 секунд, используемых всеми запросами; вы должны переместить его внутрь цикла for, чтобы каждый запрос мог иметь контекст 10 секунд.
В идеале вы не хотите, чтобы это отложение продолжало складываться; поэтому вы можете либо
- Переместите его в другую функцию (или создайте встроенную функцию и вызовите ее) Это гарантирует, что функция defer вызывается каждый раз и не складывается.
- Вызовите функцию отмены в конце цикла вручную.