Skip to content

Commit e73dae6

Browse files
committed
chore: improvements
Signed-off-by: Danny Kopping <dannykopping@gmail.com>
1 parent 562b56d commit e73dae6

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

enterprise/coderd/prebuilds/metricscollector.go

+17-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package prebuilds
22

33
import (
44
"context"
5+
"fmt"
56
"sync/atomic"
67
"time"
78

@@ -11,7 +12,6 @@ import (
1112
"cdr.dev/slog"
1213

1314
"github.com/coder/coder/v2/coderd/database"
14-
"github.com/coder/coder/v2/coderd/database/dbauthz"
1515
"github.com/coder/coder/v2/coderd/prebuilds"
1616
)
1717

@@ -57,6 +57,12 @@ var (
5757
labels,
5858
nil,
5959
)
60+
lastUpdateDesc = prometheus.NewDesc(
61+
"coderd_prebuilt_workspaces_metrics_last_updated",
62+
"The unix timestamp when the metrics related to prebuilt workspaces were last updated; these metrics are cached.",
63+
[]string{},
64+
nil,
65+
)
6066
)
6167

6268
const (
@@ -91,18 +97,16 @@ func (*MetricsCollector) Describe(descCh chan<- *prometheus.Desc) {
9197
descCh <- desiredPrebuildsDesc
9298
descCh <- runningPrebuildsDesc
9399
descCh <- eligiblePrebuildsDesc
100+
descCh <- lastUpdateDesc
94101
}
95102

96103
// Collect uses the cached state to set configured metrics.
97104
// The state is cached because this function can be called multiple times per second and retrieving the current state
98105
// is an expensive operation.
99106
func (mc *MetricsCollector) Collect(metricsCh chan<- prometheus.Metric) {
100-
// nolint:gocritic // We need to set an authz context to read metrics from the db.
101-
ctx := dbauthz.AsPrebuildsOrchestrator(context.Background())
102-
103-
currentState := mc.latestState.Load()
107+
currentState := mc.latestState.Load() // Grab a copy; it's ok if it goes stale during the course of this func.
104108
if currentState == nil {
105-
mc.logger.Warn(ctx, "failed to set prebuilds metrics; state not set")
109+
mc.logger.Warn(context.Background(), "failed to set prebuilds metrics; state not set")
106110
return
107111
}
108112

@@ -119,7 +123,7 @@ func (mc *MetricsCollector) Collect(metricsCh chan<- prometheus.Metric) {
119123

120124
presetSnapshot, err := currentState.snapshot.FilterByPreset(preset.ID)
121125
if err != nil {
122-
mc.logger.Error(ctx, "failed to filter by preset", slog.Error(err))
126+
mc.logger.Error(context.Background(), "failed to filter by preset", slog.Error(err))
123127
continue
124128
}
125129
state := presetSnapshot.CalculateState()
@@ -128,11 +132,14 @@ func (mc *MetricsCollector) Collect(metricsCh chan<- prometheus.Metric) {
128132
metricsCh <- prometheus.MustNewConstMetric(runningPrebuildsDesc, prometheus.GaugeValue, float64(state.Actual), preset.TemplateName, preset.Name, preset.OrganizationName)
129133
metricsCh <- prometheus.MustNewConstMetric(eligiblePrebuildsDesc, prometheus.GaugeValue, float64(state.Eligible), preset.TemplateName, preset.Name, preset.OrganizationName)
130134
}
135+
136+
metricsCh <- prometheus.MustNewConstMetric(lastUpdateDesc, prometheus.GaugeValue, float64(currentState.createdAt.Unix()))
131137
}
132138

133139
type state struct {
134140
prebuildMetrics []database.GetPrebuildMetricsRow
135141
snapshot *prebuilds.GlobalSnapshot
142+
createdAt time.Time
136143
}
137144

138145
// BackgroundFetch updates the metrics state every given interval.
@@ -157,6 +164,7 @@ func (mc *MetricsCollector) BackgroundFetch(ctx context.Context, updateInterval,
157164

158165
// UpdateState builds the current metrics state.
159166
func (mc *MetricsCollector) UpdateState(ctx context.Context, timeout time.Duration) error {
167+
start := time.Now()
160168
mc.logger.Debug(ctx, "fetching prebuilds metrics state")
161169
fetchCtx, fetchCancel := context.WithTimeout(ctx, timeout)
162170
defer fetchCancel()
@@ -170,11 +178,12 @@ func (mc *MetricsCollector) UpdateState(ctx context.Context, timeout time.Durati
170178
if err != nil {
171179
return xerrors.Errorf("snapshot state: %w", err)
172180
}
173-
mc.logger.Debug(ctx, "fetched prebuilds metrics state")
181+
mc.logger.Debug(ctx, "fetched prebuilds metrics state", slog.F("duration_secs", fmt.Sprintf("%.2f", time.Since(start).Seconds())))
174182

175183
mc.latestState.Store(&state{
176184
prebuildMetrics: prebuildMetrics,
177185
snapshot: snapshot,
186+
createdAt: time.Now(),
178187
})
179188
return nil
180189
}

enterprise/coderd/prebuilds/reconcile.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"database/sql"
66
"fmt"
77
"math"
8+
"sync"
89
"sync/atomic"
910
"time"
1011

@@ -87,10 +88,12 @@ func (c *StoreReconciler) Run(ctx context.Context) {
8788
slog.F("backoff_interval", c.cfg.ReconciliationBackoffInterval.String()),
8889
slog.F("backoff_lookback", c.cfg.ReconciliationBackoffLookback.String()))
8990

91+
var wg sync.WaitGroup
9092
ticker := c.clock.NewTicker(reconciliationInterval)
9193
defer ticker.Stop()
9294
defer func() {
9395
c.done <- struct{}{}
96+
wg.Wait()
9497
}()
9598

9699
// nolint:gocritic // Reconciliation Loop needs Prebuilds Orchestrator permissions.
@@ -99,7 +102,11 @@ func (c *StoreReconciler) Run(ctx context.Context) {
99102

100103
// Start updating metrics in the background.
101104
if c.metrics != nil {
102-
go c.metrics.BackgroundFetch(ctx, metricsUpdateInterval, metricsUpdateTimeout)
105+
wg.Add(1)
106+
go func() {
107+
defer wg.Done()
108+
c.metrics.BackgroundFetch(ctx, metricsUpdateInterval, metricsUpdateTimeout)
109+
}()
103110
}
104111

105112
// Everything is in place, reconciler can now be considered as running.

0 commit comments

Comments
 (0)