| 37 | } |
| 38 | |
| 39 | func (a *StatsAPI) UpdateStats(ctx context.Context, req *agentproto.UpdateStatsRequest) (*agentproto.UpdateStatsResponse, error) { |
| 40 | res := &agentproto.UpdateStatsResponse{ |
| 41 | ReportInterval: durationpb.New(a.AgentStatsRefreshInterval), |
| 42 | } |
| 43 | // An empty stat means it's just looking for the report interval. |
| 44 | if req.Stats == nil { |
| 45 | return res, nil |
| 46 | } |
| 47 | |
| 48 | // If cache is empty (prebuild or invalid), fall back to DB |
| 49 | var ws database.WorkspaceIdentity |
| 50 | var ok bool |
| 51 | if ws, ok = a.Workspace.AsWorkspaceIdentity(); !ok { |
| 52 | w, err := a.Database.GetWorkspaceByAgentID(ctx, a.AgentID) |
| 53 | if err != nil { |
| 54 | return nil, xerrors.Errorf("get workspace by agent ID %q: %w", a.AgentID, err) |
| 55 | } |
| 56 | ws = database.WorkspaceIdentityFromWorkspace(w) |
| 57 | } |
| 58 | |
| 59 | a.Log.Debug(ctx, "read stats report", |
| 60 | slog.F("interval", a.AgentStatsRefreshInterval), |
| 61 | slog.F("workspace_id", ws.ID), |
| 62 | slog.F("payload", req), |
| 63 | ) |
| 64 | |
| 65 | if a.Experiments.Enabled(codersdk.ExperimentWorkspaceUsage) { |
| 66 | // while the experiment is enabled we will not report |
| 67 | // session stats from the agent. This is because it is |
| 68 | // being handled by the CLI and the postWorkspaceUsage route. |
| 69 | req.Stats.SessionCountSsh = 0 |
| 70 | req.Stats.SessionCountJetbrains = 0 |
| 71 | req.Stats.SessionCountVscode = 0 |
| 72 | req.Stats.SessionCountReconnectingPty = 0 |
| 73 | } |
| 74 | |
| 75 | err := a.StatsReporter.ReportAgentStats( |
| 76 | ctx, |
| 77 | a.now(), |
| 78 | ws, |
| 79 | a.AgentID, |
| 80 | a.AgentName, |
| 81 | req.Stats, |
| 82 | false, |
| 83 | ) |
| 84 | if err != nil { |
| 85 | return nil, xerrors.Errorf("report agent stats: %w", err) |
| 86 | } |
| 87 | |
| 88 | return res, nil |
| 89 | } |