mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
chore: accept payload on workspace usage route (#13544)
This commit is contained in:
@ -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
|
||||
|
@ -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():
|
||||
|
Reference in New Issue
Block a user