chore: accept payload on workspace usage route (#13544)

This commit is contained in:
Garrett Delfosse
2024-06-14 10:08:45 -04:00
committed by GitHub
parent 87820a29d7
commit 44d69139d5
9 changed files with 452 additions and 15 deletions

View File

@ -2233,6 +2233,7 @@ const (
ExperimentAutoFillParameters Experiment = "auto-fill-parameters" // This should not be taken out of experiments until we have redesigned the feature.
ExperimentMultiOrganization Experiment = "multi-organization" // Requires organization context for interactions, default org is assumed.
ExperimentCustomRoles Experiment = "custom-roles" // Allows creating runtime custom roles
ExperimentWorkspaceUsage Experiment = "workspace-usage" // Enables the new workspace usage tracking
)
// ExperimentsAll should include all experiments that are safe for

View File

@ -316,7 +316,43 @@ func (c *Client) PutExtendWorkspace(ctx context.Context, id uuid.UUID, req PutEx
return nil
}
type PostWorkspaceUsageRequest struct {
AgentID uuid.UUID `json:"agent_id" format:"uuid"`
AppName UsageAppName `json:"app_name"`
}
type UsageAppName string
const (
UsageAppNameVscode UsageAppName = "vscode"
UsageAppNameJetbrains UsageAppName = "jetbrains"
UsageAppNameReconnectingPty UsageAppName = "reconnecting-pty"
UsageAppNameSSH UsageAppName = "ssh"
)
var AllowedAppNames = []UsageAppName{
UsageAppNameVscode,
UsageAppNameJetbrains,
UsageAppNameReconnectingPty,
UsageAppNameSSH,
}
// PostWorkspaceUsage marks the workspace as having been used recently and records an app stat.
func (c *Client) PostWorkspaceUsageWithBody(ctx context.Context, id uuid.UUID, req PostWorkspaceUsageRequest) error {
path := fmt.Sprintf("/api/v2/workspaces/%s/usage", id.String())
res, err := c.Request(ctx, http.MethodPost, path, req)
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
}
// PostWorkspaceUsage marks the workspace as having been used recently.
// Deprecated: use PostWorkspaceUsageWithBody instead
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)
@ -330,14 +366,15 @@ func (c *Client) PostWorkspaceUsage(ctx context.Context, id uuid.UUID) error {
return nil
}
// UpdateWorkspaceUsageContext periodically posts workspace usage for the workspace
// with the given id in the background.
// UpdateWorkspaceUsageWithBodyContext periodically posts workspace usage for the workspace
// with the given id and app name 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() {
func (c *Client) UpdateWorkspaceUsageWithBodyContext(ctx context.Context, workspaceID uuid.UUID, req PostWorkspaceUsageRequest) func() {
hbCtx, hbCancel := context.WithCancel(ctx)
// Perform one initial update
if err := c.PostWorkspaceUsage(hbCtx, id); err != nil {
err := c.PostWorkspaceUsageWithBody(hbCtx, workspaceID, req)
if err != nil {
c.logger.Warn(ctx, "failed to post workspace usage", slog.Error(err))
}
ticker := time.NewTicker(time.Minute)
@ -350,7 +387,45 @@ func (c *Client) UpdateWorkspaceUsageContext(ctx context.Context, id uuid.UUID)
for {
select {
case <-ticker.C:
if err := c.PostWorkspaceUsage(hbCtx, id); err != nil {
err := c.PostWorkspaceUsageWithBody(hbCtx, workspaceID, req)
if err != nil {
c.logger.Warn(ctx, "failed to post workspace usage in background", slog.Error(err))
}
case <-hbCtx.Done():
return
}
}
}()
return func() {
hbCancel()
<-doneCh
}
}
// 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.
// Deprecated: use UpdateWorkspaceUsageContextWithBody instead
func (c *Client) UpdateWorkspaceUsageContext(ctx context.Context, workspaceID uuid.UUID) func() {
hbCtx, hbCancel := context.WithCancel(ctx)
// Perform one initial update
err := c.PostWorkspaceUsage(hbCtx, workspaceID)
if 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:
err := c.PostWorkspaceUsage(hbCtx, workspaceID)
if err != nil {
c.logger.Warn(ctx, "failed to post workspace usage in background", slog.Error(err))
}
case <-hbCtx.Done():