Skip to content

Commit fcbfb7f

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

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

enterprise/coderd/prebuilds/metricscollector.go

+17-9
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 (
@@ -74,7 +80,6 @@ type MetricsCollector struct {
7480

7581
var _ prometheus.Collector = new(MetricsCollector)
7682

77-
// NewMetricsCollector returns a
7883
func NewMetricsCollector(db database.Store, logger slog.Logger, snapshotter prebuilds.StateSnapshotter) *MetricsCollector {
7984
log := logger.Named("prebuilds_metrics_collector")
8085
return &MetricsCollector{
@@ -91,18 +96,16 @@ func (*MetricsCollector) Describe(descCh chan<- *prometheus.Desc) {
9196
descCh <- desiredPrebuildsDesc
9297
descCh <- runningPrebuildsDesc
9398
descCh <- eligiblePrebuildsDesc
99+
descCh <- lastUpdateDesc
94100
}
95101

96102
// Collect uses the cached state to set configured metrics.
97103
// The state is cached because this function can be called multiple times per second and retrieving the current state
98104
// is an expensive operation.
99105
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()
106+
currentState := mc.latestState.Load() // Grab a copy; it's ok if it goes stale during the course of this func.
104107
if currentState == nil {
105-
mc.logger.Warn(ctx, "failed to set prebuilds metrics; state not set")
108+
mc.logger.Warn(context.Background(), "failed to set prebuilds metrics; state not set")
106109
return
107110
}
108111

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

120123
presetSnapshot, err := currentState.snapshot.FilterByPreset(preset.ID)
121124
if err != nil {
122-
mc.logger.Error(ctx, "failed to filter by preset", slog.Error(err))
125+
mc.logger.Error(context.Background(), "failed to filter by preset", slog.Error(err))
123126
continue
124127
}
125128
state := presetSnapshot.CalculateState()
@@ -128,11 +131,14 @@ func (mc *MetricsCollector) Collect(metricsCh chan<- prometheus.Metric) {
128131
metricsCh <- prometheus.MustNewConstMetric(runningPrebuildsDesc, prometheus.GaugeValue, float64(state.Actual), preset.TemplateName, preset.Name, preset.OrganizationName)
129132
metricsCh <- prometheus.MustNewConstMetric(eligiblePrebuildsDesc, prometheus.GaugeValue, float64(state.Eligible), preset.TemplateName, preset.Name, preset.OrganizationName)
130133
}
134+
135+
metricsCh <- prometheus.MustNewConstMetric(lastUpdateDesc, prometheus.GaugeValue, float64(currentState.createdAt.Unix()))
131136
}
132137

133138
type state struct {
134139
prebuildMetrics []database.GetPrebuildMetricsRow
135140
snapshot *prebuilds.GlobalSnapshot
141+
createdAt time.Time
136142
}
137143

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

158164
// UpdateState builds the current metrics state.
159165
func (mc *MetricsCollector) UpdateState(ctx context.Context, timeout time.Duration) error {
166+
start := time.Now()
160167
mc.logger.Debug(ctx, "fetching prebuilds metrics state")
161168
fetchCtx, fetchCancel := context.WithTimeout(ctx, timeout)
162169
defer fetchCancel()
@@ -170,11 +177,12 @@ func (mc *MetricsCollector) UpdateState(ctx context.Context, timeout time.Durati
170177
if err != nil {
171178
return xerrors.Errorf("snapshot state: %w", err)
172179
}
173-
mc.logger.Debug(ctx, "fetched prebuilds metrics state")
180+
mc.logger.Debug(ctx, "fetched prebuilds metrics state", slog.F("duration_secs", fmt.Sprintf("%.2f", time.Since(start).Seconds())))
174181

175182
mc.latestState.Store(&state{
176183
prebuildMetrics: prebuildMetrics,
177184
snapshot: snapshot,
185+
createdAt: time.Now(),
178186
})
179187
return nil
180188
}

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)