metricator/internal/application/fetcher.go

86 lines
1.8 KiB
Go

package application
import (
"net/http"
"time"
)
// Fetches data from remote endpoint, parses it and updates in storage.
func (a *Application) fetch() {
// Do not do anything if fetching is running.
// ToDo: maybe another approach?
a.fetchIsRunningMutex.RLock()
// This is an optimization to avoid excessive waiting when using Lock().
// Most of time application will wait between fetches.
// nolint:ifshort
isFetching := a.fetchIsRunning
a.fetchIsRunningMutex.RUnlock()
if isFetching {
return
}
a.fetchIsRunningMutex.Lock()
a.fetchIsRunning = true
a.fetchIsRunningMutex.Unlock()
a.logger.Infoln("Fetching data for", a.name)
req, err := http.NewRequestWithContext(a.ctx, "GET", a.config.Endpoint, nil)
if err != nil {
a.logger.Infoln("Failed to create request for", a.name, "metrics:", err.Error())
return
}
for header, value := range a.config.Headers {
req.Header.Add(header, value)
}
resp, err := a.httpClient.Do(req)
if err != nil {
a.logger.Infoln("Failed to execute request for", a.name, "metrics:", err.Error())
return
}
defer resp.Body.Close()
data, err := a.parse(resp.Body)
if err != nil {
a.logger.Infoln("Failed to parse response body for", a.name, "metrics:", err.Error())
return
}
a.storage.Put(data)
a.fetchIsRunningMutex.Lock()
a.fetchIsRunning = false
a.fetchIsRunningMutex.Unlock()
}
// Configures and starts Prometheus data fetching goroutine.
func (a *Application) startFetcher() {
fetchTicker := time.NewTicker(a.config.TimeBetweenRequests)
// nolint:exhaustivestruct
a.httpClient = &http.Client{
Timeout: time.Second * 5,
}
defer a.logger.Debugln("Fetcher for", a.name, "completed")
// First fetch should be executed ASAP.
a.fetch()
for {
select {
case <-a.ctx.Done():
return
case <-fetchTicker.C:
a.fetch()
}
}
}