fix(cli): port-forward: update workspace last_used_at (#12659)

This PR updates the coder port-forward command to periodically inform coderd that the workspace is being used:

- Adds workspaceusage.Tracker which periodically batch-updates workspace LastUsedAt
- Adds coderd endpoint to signal workspace usage
- Updates coder port-forward to periodically hit this endpoint
- Modifies BatchUpdateWorkspacesLastUsedAt to avoid overwriting with stale data

Co-authored-by: Danny Kopping <danny@coder.com>
This commit is contained in:
Cian Johnston
2024-03-20 16:44:12 +00:00
committed by GitHub
co-authored by Danny Kopping
parent d789a60d47
commit 92aa1eba97
15 changed files with 708 additions and 2 deletions
+50
View File
@@ -11,6 +11,8 @@ import (
"github.com/google/uuid"
"golang.org/x/xerrors"
"cdr.dev/slog"
"github.com/coder/coder/v2/coderd/tracing"
)
@@ -314,6 +316,54 @@ func (c *Client) PutExtendWorkspace(ctx context.Context, id uuid.UUID, req PutEx
return nil
}
// PostWorkspaceUsage marks the workspace as having been used recently.
func (c *Client) PostWorkspaceUsage(ctx context.Context, id uuid.UUID) error {
path := fmt.Sprintf("/api/v2/workspaces/%s/usage", id.String())
res, err := c.Request(ctx, http.MethodPost, path, nil)
if err != nil {
return xerrors.Errorf("post workspace usage: %w", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusNoContent {
return ReadBodyAsError(res)
}
return nil
}
// UpdateWorkspaceUsageContext periodically posts workspace usage for the workspace
// with the given id in the background.
// The caller is responsible for calling the returned function to stop the background
// process.
func (c *Client) UpdateWorkspaceUsageContext(ctx context.Context, id uuid.UUID) func() {
hbCtx, hbCancel := context.WithCancel(ctx)
// Perform one initial update
if err := c.PostWorkspaceUsage(hbCtx, id); err != nil {
c.logger.Warn(ctx, "failed to post workspace usage", slog.Error(err))
}
ticker := time.NewTicker(time.Minute)
doneCh := make(chan struct{})
go func() {
defer func() {
ticker.Stop()
close(doneCh)
}()
for {
select {
case <-ticker.C:
if err := c.PostWorkspaceUsage(hbCtx, id); err != nil {
c.logger.Warn(ctx, "failed to post workspace usage in background", slog.Error(err))
}
case <-hbCtx.Done():
return
}
}
}()
return func() {
hbCancel()
<-doneCh
}
}
// UpdateWorkspaceDormancy is a request to activate or make a workspace dormant.
// A value of false will activate a dormant workspace.
type UpdateWorkspaceDormancy struct {