Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cli/configssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,10 +489,14 @@ func (r *RootCmd) configSSH() *serpent.Command {
for _, ws := range res.Workspaces {
wsNames = append(wsNames, ws.Name)
}
if len(res.Workspaces) < pageSize {
// The endpoint applies its limit in SQL and then drops rows whose
// build or template the caller cannot read, so a page shorter than
// pageSize does not mean the result set is exhausted. Count is the
// total before the limit and offset are applied.
offset += pageSize
if offset >= res.Count {
break
}
offset += pageSize
}
configOptions.workspaceNames = wsNames
}
Expand Down
17 changes: 13 additions & 4 deletions cli/exp_scaletest.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,11 @@ func getScaletestPrebuildWorkspaces(ctx context.Context, client *codersdk.Client
result = append(result, ws)
}
}
if len(resp.Workspaces) < pageSize {
// The endpoint applies its limit in SQL and then drops rows whose build
// or template the caller cannot read, so a page shorter than pageSize
// does not mean the result set is exhausted. Count is the total before
// the limit and offset are applied.
if (page+1)*pageSize >= resp.Count {
break
}
}
Expand Down Expand Up @@ -2249,9 +2253,6 @@ func getScaletestWorkspaces(ctx context.Context, client *codersdk.Client, owner,
}

pageNumber++
if len(page.Workspaces) == 0 {
break
}

pageWorkspaces := make([]codersdk.Workspace, 0, len(page.Workspaces))
for _, w := range page.Workspaces {
Expand All @@ -2265,6 +2266,14 @@ func getScaletestWorkspaces(ctx context.Context, client *codersdk.Client, owner,
pageWorkspaces = append(pageWorkspaces, w)
}
workspaces = append(workspaces, pageWorkspaces...)

// The endpoint applies its limit in SQL and then drops rows whose build or
// template the caller cannot read, so a short or empty page does not mean
// the result set is exhausted. Count is the total before the limit and
// offset are applied.
if pageNumber*limit >= page.Count {
break
}
}
return workspaces, skipped, nil
}
Expand Down
20 changes: 20 additions & 0 deletions coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -2820,6 +2820,10 @@ func convertWorkspaces(
appStatusesByWorkspaceID[appStatus.WorkspaceID] = appStatus
}

var (
missingBuilds int
missingTemplates int
)
apiWorkspaces := make([]codersdk.Workspace, 0, len(workspaces))
for _, workspace := range workspaces {
// If any data is missing from the workspace, just skip returning
Expand All @@ -2829,10 +2833,12 @@ func convertWorkspaces(
// fields?
build, exists := buildByWorkspaceID[workspace.ID]
if !exists {
missingBuilds++
continue
}
template, exists := templateByID[workspace.TemplateID]
if !exists {
missingTemplates++
continue
}
appStatus := appStatusesByWorkspaceID[workspace.ID]
Expand All @@ -2853,6 +2859,20 @@ func convertWorkspaces(

apiWorkspaces = append(apiWorkspaces, w)
}

// Dropped workspaces make the returned slice shorter than the rows it was
// built from, which callers cannot distinguish from an exhausted result
// set when the rows came from a limited query.
if dropped := len(workspaces) - len(apiWorkspaces); dropped > 0 {
logger.Warn(ctx, "dropped workspaces missing build or template data",
slog.F("requester_id", requesterID),
slog.F("rows", len(workspaces)),
slog.F("dropped", dropped),
slog.F("missing_builds", missingBuilds),
slog.F("missing_templates", missingTemplates),
)
}

return apiWorkspaces, nil
}

Expand Down
6 changes: 5 additions & 1 deletion scaletest/prebuilds/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,11 @@ func allWorkspacesForTemplate(ctx context.Context, client *codersdk.Client, temp
return nil, xerrors.Errorf("list workspaces page %d: %w", page, err)
}
workspaces = append(workspaces, resp.Workspaces...)
if len(resp.Workspaces) < pageSize {
// The endpoint applies its limit in SQL and then drops rows whose build or
// template the caller cannot read, so a page shorter than pageSize does not
// mean the result set is exhausted. Count is the total before the limit and
// offset are applied.
if (page+1)*pageSize >= resp.Count {
break
}
}
Expand Down
9 changes: 7 additions & 2 deletions support/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,15 @@ func DeploymentInfo(ctx context.Context, client *codersdk.Client, log slog.Logge
}
break
}
if offset+len(resp.Workspaces) >= count || len(resp.Workspaces) == 0 {
// The offset advances by the requested limit rather than the number of
// rows returned. The endpoint applies its limit in SQL and then drops
// rows whose build or template the caller cannot read, so advancing by
// len(resp.Workspaces) would re-request rows already collected. Count is
// the total before the limit and offset are applied.
offset += limit
if offset >= count {
break
}
offset += len(resp.Workspaces)
}
if d.Workspaces != nil {
// Replace with aggregated list
Expand Down
Loading