@@ -4,6 +4,7 @@ import (
|
4 | 4 | "context" |
5 | 5 | "database/sql" |
6 | 6 | "slices" |
| 7 | +"sync" |
7 | 8 | "time" |
8 | 9 | |
9 | 10 | "github.com/google/uuid" |
@@ -31,7 +32,9 @@ type LifecycleAPI struct {
|
31 | 32 | Log slog.Logger |
32 | 33 | PublishWorkspaceUpdateFn func(context.Context, *database.WorkspaceAgent, wspubsub.WorkspaceEventKind) error |
33 | 34 | |
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 |
35 | 38 | } |
36 | 39 | |
37 | 40 | func (a *LifecycleAPI) now() time.Time { |
@@ -125,6 +128,17 @@ func (a *LifecycleAPI) UpdateLifecycle(ctx context.Context, req *agentproto.Upda
|
125 | 128 | } |
126 | 129 | } |
127 | 130 | |
| 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 | + |
128 | 142 | return req.Lifecycle, nil |
129 | 143 | } |
130 | 144 | |
|