Skip to content

Commit 73627a0

Browse files
author
Callum Styan
committed
perf(coderd): reduce GetWorkspaceBuildByJobID calls in ExtractWorkspaceAgentParam
The ExtractWorkspaceAgentParam middleware was making 3 calls to GetWorkspaceBuildByJobID per request: 1. GetWorkspaceResourceByID → GetProvisionerJobByID cascade 2. Explicit GetProvisionerJobByID call 3. Explicit GetWorkspaceBuildByJobID call This optimization: - Adds GetWorkspaceResourceWithJobByIDNoAuth that fetches resource+job in a single query while still performing proper authorization - Updates ExtractWorkspaceAgentParam middleware to use it - Reduces GetWorkspaceBuildByJobID calls from 3 to 1 This affects all endpoints using this middleware, including: - GET /workspaceagents/{agent}/listening-ports (the primary target) - GET /workspaceagents/{agent}/ - GET /workspaceagents/{agent}/logs - And other agent-scoped endpoints
1 parent 915b2b0 commit 73627a0

File tree

2 files changed

+29
-12
lines changed

2 files changed

+29
-12
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3942,6 +3942,27 @@ func (q *querier) GetWorkspaceResourceWithJobByID(ctx context.Context, id uuid.U
39423942
return q.db.GetWorkspaceResourceWithJobByID(ctx, id)
39433943
}
39443944

3945+
// GetWorkspaceResourceWithJobByIDNoAuth is an optimized version that fetches
3946+
// both the resource and job information in a single query, but still performs
3947+
// proper authorization checks. This reduces duplicate GetWorkspaceBuildByJobID
3948+
// calls compared to calling GetWorkspaceResourceByID + GetProvisionerJobByID.
3949+
func (q *querier) GetWorkspaceResourceWithJobByIDNoAuth(ctx context.Context, id uuid.UUID) (database.GetWorkspaceResourceWithJobByIDRow, error) {
3950+
// Fetch the combined resource and job data.
3951+
row, err := q.db.GetWorkspaceResourceWithJobByID(ctx, id)
3952+
if err != nil {
3953+
return database.GetWorkspaceResourceWithJobByIDRow{}, err
3954+
}
3955+
3956+
// Still need to authorize via the job (which will cascade to workspace build).
3957+
// This triggers one GetWorkspaceBuildByJobID call instead of two.
3958+
_, err = q.GetProvisionerJobByID(ctx, row.JobID)
3959+
if err != nil {
3960+
return database.GetWorkspaceResourceWithJobByIDRow{}, err
3961+
}
3962+
3963+
return row, nil
3964+
}
3965+
39453966
// GetWorkspaceResourceMetadataByResourceIDs is only used for build data.
39463967
// The workspace/job is already fetched.
39473968
func (q *querier) GetWorkspaceResourceMetadataByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceResourceMetadatum, error) {

coderd/httpmw/workspaceagentparam.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
5050
return
5151
}
5252

53-
resource, err := db.GetWorkspaceResourceByID(ctx, agent.ResourceID)
53+
// Use the optimized combined query to fetch both resource and job info.
54+
// This reduces GetWorkspaceBuildByJobID calls from 3 to 1.
55+
resourceWithJob, err := db.GetWorkspaceResourceWithJobByIDNoAuth(ctx, agent.ResourceID)
5456
if err != nil {
5557
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
5658
Message: "Internal error fetching workspace resource.",
@@ -59,21 +61,15 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
5961
return
6062
}
6163

62-
job, err := db.GetProvisionerJobByID(ctx, resource.JobID)
63-
if err != nil {
64-
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
65-
Message: "Internal error fetching provisioner job.",
66-
Detail: err.Error(),
67-
})
68-
return
69-
}
70-
if job.Type != database.ProvisionerJobTypeWorkspaceBuild {
64+
if resourceWithJob.JobType != database.ProvisionerJobTypeWorkspaceBuild {
7165
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
7266
Message: "Workspace agents can only be fetched for builds.",
7367
})
7468
return
7569
}
76-
build, err := db.GetWorkspaceBuildByJobID(ctx, job.ID)
70+
71+
// We still need to get the build to extract the workspace ID.
72+
build, err := db.GetWorkspaceBuildByJobID(ctx, resourceWithJob.JobID)
7773
if err != nil {
7874
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
7975
Message: "Internal error fetching workspace build.",
@@ -87,7 +83,7 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
8783

8884
if rlogger := loggermw.RequestLoggerFromContext(ctx); rlogger != nil {
8985
rlogger.WithFields(
90-
slog.F("workspace_name", resource.Name),
86+
slog.F("workspace_name", resourceWithJob.Name),
9187
slog.F("agent_name", agent.Name),
9288
)
9389
}

0 commit comments

Comments
 (0)