trackWorkspaceUsage bumps the workspace's last_used_at via the usage tracker and extends the workspace's autostop deadline. If wsID is not yet valid, it re-reads the chat from the DB to pick up late associations (e.g. create_workspace linking a workspace mid-conversation). The caller should store th
( ctx context.Context, chatID uuid.UUID, wsID uuid.NullUUID, logger slog.Logger, )
| 5967 | // that subsequent calls skip the DB lookup once a workspace has |
| 5968 | // been found. |
| 5969 | func (p *Server) trackWorkspaceUsage( |
| 5970 | ctx context.Context, |
| 5971 | chatID uuid.UUID, |
| 5972 | wsID uuid.NullUUID, |
| 5973 | logger slog.Logger, |
| 5974 | ) uuid.NullUUID { |
| 5975 | if p.usageTracker == nil { |
| 5976 | return wsID |
| 5977 | } |
| 5978 | if !wsID.Valid { |
| 5979 | latest, err := p.db.GetChatByID(ctx, chatID) |
| 5980 | if err != nil { |
| 5981 | logger.Warn(ctx, "failed to re-read chat for workspace association", slog.Error(err)) |
| 5982 | return wsID |
| 5983 | } |
| 5984 | wsID = latest.WorkspaceID |
| 5985 | } |
| 5986 | if wsID.Valid { |
| 5987 | p.usageTracker.Add(wsID.UUID) |
| 5988 | // Bump the workspace autostop deadline. We pass time.Time{} |
| 5989 | // for nextAutostart since we don't have access to |
| 5990 | // TemplateScheduleStore here. The activity bump logic |
| 5991 | // defaults to the template's activity_bump duration |
| 5992 | // (typically 1 hour). Chat workspaces are never prebuilds, |
| 5993 | // so no prebuild guard is needed (unlike reporter.go). |
| 5994 | // |
| 5995 | // This fires every heartbeat (~30s) but the SQL only |
| 5996 | // writes when 5% of the deadline has elapsed — most calls |
| 5997 | // perform a read-only CTE lookup with no UPDATE. |
| 5998 | // |
| 5999 | // Scaling note: for 10,000 active chats, this could lead to |
| 6000 | // approx. 333 CTE queries/second. A cheap fix for this could |
| 6001 | // be to heartbeat every Nth query. Leaving as potential future |
| 6002 | // low-hanging fruit if needed. |
| 6003 | workspacestats.ActivityBumpWorkspace(ctx, logger.Named("activity_bump"), p.db, wsID.UUID, time.Time{}, workspacestats.ActivityBumpReasonChatHeartbeat) |
| 6004 | } |
| 6005 | return wsID |
| 6006 | } |
| 6007 | |
| 6008 | type finishActiveChatResult struct { |
| 6009 | updatedChat database.Chat |
no test coverage detected