Skip to content

Commit 605116f

Browse files
authored
Merge c8bcd8b into 17ba68c
2 parents 17ba68c + c8bcd8b commit 605116f

File tree

2 files changed

+69
-17
lines changed

2 files changed

+69
-17
lines changed

internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ func (cfg *Config) applyEnv() {
154154
cfg.APIBaseURL = env.FirstOrDefault(cfg.APIBaseURL, apiBaseURLEnvKey)
155155
cfg.FlapsBaseURL = env.FirstOrDefault(cfg.FlapsBaseURL, flapsBaseURLEnvKey)
156156
cfg.MetricsBaseURL = env.FirstOrDefault(cfg.MetricsBaseURL, metricsBaseURLEnvKey)
157+
cfg.MetricsToken = env.FirstOrDefault(cfg.MetricsToken, MetricsTokenEnvKey, AccessTokenEnvKey, APITokenEnvKey)
157158
cfg.SyntheticsBaseURL = env.FirstOrDefault(cfg.SyntheticsBaseURL, syntheticsBaseURLEnvKey)
158159
cfg.SendMetrics = env.IsTruthy(SendMetricsEnvKey) || cfg.SendMetrics
159160
cfg.SyntheticsAgent = env.IsTruthy(SyntheticsAgentEnvKey) || cfg.SyntheticsAgent

internal/metrics/db.go

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"encoding/json"
77
"fmt"
8+
"io"
89
"net/http"
910
"os"
1011
"os/exec"
@@ -38,8 +39,6 @@ func FlushMetrics(ctx context.Context) error {
3839

3940
iostream := iostreams.FromContext(ctx)
4041

41-
// On CI, always block on metrics send. This sucks, but the alternative is not getting metrics from CI at all. There are timeouts in place to prevent this from taking more than 15 seconds
42-
4342
if iostream.IsInteractive() {
4443
flyctl, err := os.Executable()
4544
if err != nil {
@@ -76,33 +75,85 @@ func FlushMetrics(ctx context.Context) error {
7675
return nil
7776
}
7877

79-
// / Spens up to 15 seconds sending all metrics collected so far to flyctl-metrics post endpoint
80-
func SendMetrics(ctx context.Context, json string) error {
81-
authToken, err := GetMetricsToken(ctx)
78+
func SendMetrics(ctx context.Context, jsonData string) error {
79+
cfg := config.FromContext(ctx)
80+
metricsToken, err := GetMetricsToken(ctx)
8281
if err != nil {
83-
return err
82+
fmt.Fprintf(os.Stderr, "Warning: Metrics token unavailable: %v\n", err)
83+
return nil
8484
}
8585

86-
cfg := config.FromContext(ctx)
87-
request, err := http.NewRequest("POST", cfg.MetricsBaseURL+"/metrics_post", bytes.NewBuffer([]byte(json)))
86+
baseURL := cfg.MetricsBaseURL
87+
endpoint := baseURL + "/metrics_post"
88+
userAgent := fmt.Sprintf("flyctl/%s", buildinfo.Info().Version)
89+
90+
errChan := make(chan error, 1)
91+
92+
go sendMetricsRequest(endpoint, metricsToken, userAgent, []byte(jsonData), errChan)
93+
94+
err = waitForCompletion(errChan)
8895
if err != nil {
89-
return err
96+
fmt.Fprintf(os.Stderr, "Warning: Metrics send issue: %v\n", err)
97+
}
98+
99+
return nil
100+
}
101+
102+
func sendMetricsRequest(endpoint, token, userAgent string, data []byte, errChan chan<- error) {
103+
request, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(data))
104+
if err != nil {
105+
errChan <- fmt.Errorf("failed to create request: %w", err)
106+
return
90107
}
91108

92-
request.Header.Set("Authorization", authToken)
93-
request.Header.Set("User-Agent", fmt.Sprintf("flyctl/%s", buildinfo.Info().Version))
109+
request.Header.Set("Authorization", "Bearer "+token)
110+
request.Header.Set("User-Agent", userAgent)
94111

95-
retryTransport := rehttp.NewTransport(http.DefaultTransport, rehttp.RetryAll(rehttp.RetryMaxRetries(3), rehttp.RetryTimeoutErr()), rehttp.ConstDelay(0))
112+
client := createHTTPClient()
96113

97-
client := http.Client{
114+
resp, err := client.Do(request)
115+
if err != nil {
116+
errChan <- fmt.Errorf("failed to send metrics: %w", err)
117+
return
118+
}
119+
defer resp.Body.Close()
120+
121+
if resp.StatusCode != http.StatusOK {
122+
body, _ := io.ReadAll(resp.Body)
123+
errChan <- fmt.Errorf("metrics send failed with status %d: %s", resp.StatusCode, string(body))
124+
return
125+
}
126+
127+
_, err = io.Copy(io.Discard, resp.Body)
128+
if err != nil {
129+
errChan <- fmt.Errorf("failed to read response body: %w", err)
130+
return
131+
}
132+
133+
errChan <- nil
134+
}
135+
136+
func createHTTPClient() *http.Client {
137+
retryTransport := rehttp.NewTransport(
138+
http.DefaultTransport,
139+
rehttp.RetryAll(
140+
rehttp.RetryMaxRetries(3),
141+
rehttp.RetryTimeoutErr(),
142+
),
143+
rehttp.ConstDelay(0),
144+
)
145+
146+
return &http.Client{
98147
Transport: retryTransport,
99148
Timeout: time.Second * 5,
100149
}
150+
}
101151

102-
resp, err := client.Do(request)
103-
if err != nil {
152+
func waitForCompletion(errChan <-chan error) error {
153+
select {
154+
case err := <-errChan:
104155
return err
156+
case <-time.After(15 * time.Second):
157+
return fmt.Errorf("metrics send timed out after 15 seconds")
105158
}
106-
107-
return resp.Body.Close()
108159
}

0 commit comments

Comments
 (0)