Skip to content

Commit 068dbd6

Browse files
committed
fix(coderd/prometheusmetrics): no deleted wsbuilds to reduce db load
This change removes the `GetLatestWorkspaceBuilds` query which includes all workspaces for all time (including deleted). This allows us to also stop using `GetProvisionerJobsByIDs` for said builds as the job status is included in `GetWorkspaces` called separately. Fixes coder/internal#717
1 parent 408e19f commit 068dbd6

File tree

8 files changed

+93
-149
lines changed

8 files changed

+93
-149
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,17 +2157,6 @@ func (q *querier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, work
21572157
return q.db.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspaceID)
21582158
}
21592159

2160-
func (q *querier) GetLatestWorkspaceBuilds(ctx context.Context) ([]database.WorkspaceBuild, error) {
2161-
// This function is a system function until we implement a join for workspace builds.
2162-
// This is because we need to query for all related workspaces to the returned builds.
2163-
// This is a very inefficient method of fetching the latest workspace builds.
2164-
// We should just join the rbac properties.
2165-
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
2166-
return nil, err
2167-
}
2168-
return q.db.GetLatestWorkspaceBuilds(ctx)
2169-
}
2170-
21712160
func (q *querier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceBuild, error) {
21722161
// This function is a system function until we implement a join for workspace builds.
21732162
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {

coderd/database/dbmetrics/querymetrics.go

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

Lines changed: 0 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 0 additions & 59 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/workspacebuilds.sql

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,6 @@ JOIN
9191
workspace_build_with_user AS wb
9292
ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number;
9393

94-
-- name: GetLatestWorkspaceBuilds :many
95-
SELECT wb.*
96-
FROM (
97-
SELECT
98-
workspace_id, MAX(build_number) as max_build_number
99-
FROM
100-
workspace_build_with_user AS workspace_builds
101-
GROUP BY
102-
workspace_id
103-
) m
104-
JOIN
105-
workspace_build_with_user AS wb
106-
ON m.workspace_id = wb.workspace_id AND m.max_build_number = wb.build_number;
107-
10894
-- name: InsertWorkspaceBuild :exec
10995
INSERT INTO
11096
workspace_builds (

coderd/prometheusmetrics/prometheusmetrics.go

Lines changed: 19 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -168,59 +168,37 @@ func Workspaces(ctx context.Context, logger slog.Logger, registerer prometheus.R
168168
ctx, cancelFunc := context.WithCancel(ctx)
169169
done := make(chan struct{})
170170

171-
updateWorkspaceTotals := func() {
172-
builds, err := db.GetLatestWorkspaceBuilds(ctx)
173-
if err != nil {
174-
if errors.Is(err, sql.ErrNoRows) {
175-
// clear all series if there are no database entries
176-
workspaceLatestBuildTotals.Reset()
177-
} else {
178-
logger.Warn(ctx, "failed to load latest workspace builds", slog.Error(err))
179-
}
180-
return
181-
}
182-
jobIDs := make([]uuid.UUID, 0, len(builds))
183-
for _, build := range builds {
184-
jobIDs = append(jobIDs, build.JobID)
185-
}
186-
jobs, err := db.GetProvisionerJobsByIDs(ctx, jobIDs)
187-
if err != nil {
188-
ids := make([]string, 0, len(jobIDs))
189-
for _, id := range jobIDs {
190-
ids = append(ids, id.String())
191-
}
192-
193-
logger.Warn(ctx, "failed to load provisioner jobs", slog.F("ids", ids), slog.Error(err))
194-
return
195-
}
196-
197-
workspaceLatestBuildTotals.Reset()
198-
for _, job := range jobs {
199-
status := codersdk.ProvisionerJobStatus(job.JobStatus)
200-
workspaceLatestBuildTotals.WithLabelValues(string(status)).Add(1)
201-
// TODO: deprecated: remove in the future
202-
workspaceLatestBuildTotalsDeprecated.WithLabelValues(string(status)).Add(1)
203-
}
204-
}
205-
206-
updateWorkspaceStatuses := func() {
171+
updateWorkspaceMetrics := func() {
207172
ws, err := db.GetWorkspaces(ctx, database.GetWorkspacesParams{
208173
Deleted: false,
209174
WithSummary: false,
210175
})
211176
if err != nil {
212177
if errors.Is(err, sql.ErrNoRows) {
213-
// clear all series if there are no database entries
178+
workspaceLatestBuildTotals.Reset()
214179
workspaceLatestBuildStatuses.Reset()
180+
} else {
181+
logger.Warn(ctx, "failed to load active workspaces for metrics", slog.Error(err))
215182
}
216-
217-
logger.Warn(ctx, "failed to load active workspaces", slog.Error(err))
218183
return
219184
}
220185

186+
workspaceLatestBuildTotals.Reset()
221187
workspaceLatestBuildStatuses.Reset()
188+
222189
for _, w := range ws {
223-
workspaceLatestBuildStatuses.WithLabelValues(string(w.LatestBuildStatus), w.TemplateName, w.TemplateVersionName.String, w.OwnerUsername, string(w.LatestBuildTransition)).Add(1)
190+
status := string(w.LatestBuildStatus)
191+
workspaceLatestBuildTotals.WithLabelValues(status).Add(1)
192+
// TODO: deprecated: remove in the future
193+
workspaceLatestBuildTotalsDeprecated.WithLabelValues(status).Add(1)
194+
195+
workspaceLatestBuildStatuses.WithLabelValues(
196+
status,
197+
w.TemplateName,
198+
w.TemplateVersionName.String,
199+
w.OwnerUsername,
200+
string(w.LatestBuildTransition),
201+
).Add(1)
224202
}
225203
}
226204

@@ -230,8 +208,7 @@ func Workspaces(ctx context.Context, logger slog.Logger, registerer prometheus.R
230208
doTick := func() {
231209
defer ticker.Reset(duration)
232210

233-
updateWorkspaceTotals()
234-
updateWorkspaceStatuses()
211+
updateWorkspaceMetrics()
235212
}
236213

237214
go func() {

coderd/prometheusmetrics/prometheusmetrics_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,32 @@ func TestWorkspaceLatestBuildTotals(t *testing.T) {
247247
codersdk.ProvisionerJobSucceeded: 3,
248248
codersdk.ProvisionerJobRunning: 1,
249249
},
250+
}, {
251+
Name: "MultipleWithDeleted",
252+
Database: func() database.Store {
253+
db, _ := dbtestutil.NewDB(t)
254+
u := dbgen.User(t, db, database.User{})
255+
org := dbgen.Organization(t, db, database.Organization{})
256+
insertCanceled(t, db, u, org)
257+
insertFailed(t, db, u, org)
258+
insertSuccess(t, db, u, org)
259+
insertRunning(t, db, u, org)
260+
261+
// Verify that deleted workspaces/builds are NOT counted in metrics.
262+
n, err := cryptorand.Intn(5)
263+
require.NoError(t, err)
264+
for range 1 + n {
265+
insertDeleted(t, db, u, org)
266+
}
267+
return db
268+
},
269+
Total: 4, // Only non-deleted workspaces should be counted
270+
Status: map[codersdk.ProvisionerJobStatus]int{
271+
codersdk.ProvisionerJobCanceled: 1,
272+
codersdk.ProvisionerJobFailed: 1,
273+
codersdk.ProvisionerJobSucceeded: 1,
274+
codersdk.ProvisionerJobRunning: 1,
275+
},
250276
}} {
251277
t.Run(tc.Name, func(t *testing.T) {
252278
t.Parallel()
@@ -323,6 +349,33 @@ func TestWorkspaceLatestBuildStatuses(t *testing.T) {
323349
codersdk.ProvisionerJobSucceeded: 3,
324350
codersdk.ProvisionerJobRunning: 1,
325351
},
352+
}, {
353+
Name: "MultipleWithDeleted",
354+
Database: func() database.Store {
355+
db, _ := dbtestutil.NewDB(t)
356+
u := dbgen.User(t, db, database.User{})
357+
org := dbgen.Organization(t, db, database.Organization{})
358+
insertTemplates(t, db, u, org)
359+
insertCanceled(t, db, u, org)
360+
insertFailed(t, db, u, org)
361+
insertSuccess(t, db, u, org)
362+
insertRunning(t, db, u, org)
363+
364+
// Verify that deleted workspaces/builds are NOT counted in metrics.
365+
n, err := cryptorand.Intn(5)
366+
require.NoError(t, err)
367+
for range 1 + n {
368+
insertDeleted(t, db, u, org)
369+
}
370+
return db
371+
},
372+
ExpectedWorkspaces: 4, // Only non-deleted workspaces should be counted
373+
ExpectedStatuses: map[codersdk.ProvisionerJobStatus]int{
374+
codersdk.ProvisionerJobCanceled: 1,
375+
codersdk.ProvisionerJobFailed: 1,
376+
codersdk.ProvisionerJobSucceeded: 1,
377+
codersdk.ProvisionerJobRunning: 1,
378+
},
326379
}} {
327380
t.Run(tc.Name, func(t *testing.T) {
328381
t.Parallel()
@@ -907,3 +960,24 @@ func insertSuccess(t *testing.T, db database.Store, u database.User, org databas
907960
})
908961
require.NoError(t, err)
909962
}
963+
964+
func insertDeleted(t *testing.T, db database.Store, u database.User, org database.Organization) {
965+
job := insertRunning(t, db, u, org)
966+
err := db.UpdateProvisionerJobWithCompleteByID(context.Background(), database.UpdateProvisionerJobWithCompleteByIDParams{
967+
ID: job.ID,
968+
CompletedAt: sql.NullTime{
969+
Time: dbtime.Now(),
970+
Valid: true,
971+
},
972+
})
973+
require.NoError(t, err)
974+
975+
build, err := db.GetWorkspaceBuildByJobID(context.Background(), job.ID)
976+
require.NoError(t, err)
977+
978+
err = db.UpdateWorkspaceDeletedByID(context.Background(), database.UpdateWorkspaceDeletedByIDParams{
979+
ID: build.WorkspaceID,
980+
Deleted: true,
981+
})
982+
require.NoError(t, err)
983+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy