Skip to content

Commit 6035e45

Browse files
authored
feat: add e2e workspace build duration metric (#21739)
Adds coderd_template_workspace_build_duration_seconds histogram that tracks the full duration from workspace build creation to agent ready. This captures the complete user-perceived build time including provisioning and agent startup. The metric is emitted when the agent reports ready/error/timeout via the lifecycle API, ensuring each build is counted exactly once per replica.
1 parent a31e476 commit 6035e45

15 files changed

Lines changed: 525 additions & 3 deletions

File tree

coderd/agentapi/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ type Options struct {
8989
PublishWorkspaceAgentLogsUpdateFn func(ctx context.Context, workspaceAgentID uuid.UUID, msg agentsdk.LogsNotifyMessage)
9090
NetworkTelemetryHandler func(batch []*tailnetproto.TelemetryEvent)
9191
BoundaryUsageTracker *boundaryusage.Tracker
92+
LifecycleMetrics *LifecycleMetrics
9293

9394
AccessURL *url.URL
9495
AppHostname string
@@ -170,6 +171,7 @@ func New(opts Options, workspace database.Workspace) *API {
170171
Database: opts.Database,
171172
Log: opts.Log,
172173
PublishWorkspaceUpdateFn: api.publishWorkspaceUpdate,
174+
Metrics: opts.LifecycleMetrics,
173175
}
174176

175177
api.AppsAPI = &AppsAPI{

coderd/agentapi/lifecycle.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"database/sql"
66
"slices"
7+
"sync"
78
"time"
89

910
"github.com/google/uuid"
@@ -31,7 +32,9 @@ type LifecycleAPI struct {
3132
Log slog.Logger
3233
PublishWorkspaceUpdateFn func(context.Context, *database.WorkspaceAgent, wspubsub.WorkspaceEventKind) error
3334

34-
TimeNowFn func() time.Time // defaults to dbtime.Now()
35+
TimeNowFn func() time.Time // defaults to dbtime.Now()
36+
Metrics *LifecycleMetrics
37+
emitMetricsOnce sync.Once
3538
}
3639

3740
func (a *LifecycleAPI) now() time.Time {
@@ -125,6 +128,17 @@ func (a *LifecycleAPI) UpdateLifecycle(ctx context.Context, req *agentproto.Upda
125128
}
126129
}
127130

131+
// Emit build duration metric when agent transitions to a terminal startup state.
132+
// We only emit once per agent connection to avoid duplicate metrics.
133+
switch lifecycleState {
134+
case database.WorkspaceAgentLifecycleStateReady,
135+
database.WorkspaceAgentLifecycleStateStartTimeout,
136+
database.WorkspaceAgentLifecycleStateStartError:
137+
a.emitMetricsOnce.Do(func() {
138+
a.emitBuildDurationMetric(ctx, workspaceAgent.ResourceID)
139+
})
140+
}
141+
128142
return req.Lifecycle, nil
129143
}
130144

0 commit comments

Comments
 (0)