Превышен предельный срок контекста ошибки клиента Prometheus go

#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 секунд.

В идеале вы не хотите, чтобы это отложение продолжало складываться; поэтому вы можете либо

  1. Переместите его в другую функцию (или создайте встроенную функцию и вызовите ее) Это гарантирует, что функция defer вызывается каждый раз и не складывается.
  2. Вызовите функцию отмены в конце цикла вручную.