mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(coderd): render collected_at as UTC RFC3339 in the agent metadata aggregate (#27991)
Follow-up to #27934; this fix was pushed to the branch after the squash-merge and missed it. `jsonb_build_object` renders timestamptz in the session `TimeZone`, which Coder never pins, and `collected_at` defaults to year 1 until the agent's first report. On a non-UTC Postgres session a registered-but-never-collected item renders with an LMT second-offset (even `BC`, e.g. `0001-12-31T19:03:58-04:56:02 BC`), which Go's RFC3339 parsing rejects - a 500 for the entire list page whenever `include_agent_metadata` is used. - `to_char(... AT TIME ZONE 'UTC', ...)` pins the rendering; never-collected items round-trip as Go's zero time. - The test now runs against a named-zone database (`dbtestutil.WithTimezone("America/Caracas")`) and requests a registered but never-collected key; it reproduces the 500 without the fix. Also contains the failure mode Go-side: an unparsable aggregate now degrades to missing metadata for that workspace (with a warning log) instead of failing the entire page. The SQL fix prevents the known cause; the containment covers any future one. The test still catches regressions because it asserts the metadata values, not just a 200. --- Authored by Coder Agents on behalf of @Emyrk.
This commit is contained in:
+11
-12
@@ -249,14 +249,7 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if len(filter.IncludeAgentMetadata) > 0 {
|
||||
err = attachAgentMetadata(wss, workspaceRows)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error converting agent metadata.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
attachAgentMetadata(ctx, api.Logger, wss, workspaceRows)
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspacesResponse{
|
||||
@@ -2771,8 +2764,11 @@ func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspa
|
||||
|
||||
// attachAgentMetadata maps the agent metadata the workspaces query
|
||||
// aggregated per workspace onto the agents in the converted response.
|
||||
// Each aggregated datum carries its workspace_agent_id.
|
||||
func attachAgentMetadata(workspaces []codersdk.Workspace, rows []database.GetWorkspacesRow) error {
|
||||
// Each aggregated datum carries its workspace_agent_id. An unparsable
|
||||
// aggregate degrades to missing metadata for that workspace rather
|
||||
// than failing the page: the expansion is best-effort decoration on
|
||||
// top of the list.
|
||||
func attachAgentMetadata(ctx context.Context, logger slog.Logger, workspaces []codersdk.Workspace, rows []database.GetWorkspacesRow) {
|
||||
byAgent := map[uuid.UUID][]database.WorkspaceAgentMetadatum{}
|
||||
for _, row := range rows {
|
||||
if len(row.AgentMetadata) == 0 {
|
||||
@@ -2781,7 +2777,11 @@ func attachAgentMetadata(workspaces []codersdk.Workspace, rows []database.GetWor
|
||||
var metadata database.AgentMetadataAggregate
|
||||
err := metadata.Scan(row.AgentMetadata)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("scan agent metadata for workspace %q: %w", row.ID, err)
|
||||
logger.Warn(ctx, "scan agent metadata, omitting it for the workspace",
|
||||
slog.F("workspace_id", row.ID),
|
||||
slog.Error(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
for _, datum := range metadata {
|
||||
byAgent[datum.WorkspaceAgentID] = append(byAgent[datum.WorkspaceAgentID], datum)
|
||||
@@ -2798,7 +2798,6 @@ func attachAgentMetadata(workspaces []codersdk.Workspace, rows []database.GetWor
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertWorkspaces(
|
||||
|
||||
Reference in New Issue
Block a user