Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit688bb5e

Browse files
committed
Allow partial app status updates
Since we will be sending status updates without messages on an interval,we need to prevent duplicates and preserve the previous message.Also, I think this makes the endpoint more in alignment with PATCHsemantics.
1 parentf1c742e commit688bb5e

File tree

11 files changed

+203
-1
lines changed

11 files changed

+203
-1
lines changed

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,13 @@ func (q *querier) GetLatestCryptoKeyByFeature(ctx context.Context, feature datab
19911991
returnq.db.GetLatestCryptoKeyByFeature(ctx,feature)
19921992
}
19931993

1994+
func (q*querier)GetLatestWorkspaceAppStatusByAppID(ctx context.Context,appID uuid.UUID) (database.WorkspaceAppStatus,error) {
1995+
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceSystem);err!=nil {
1996+
return database.WorkspaceAppStatus{},err
1997+
}
1998+
returnq.db.GetLatestWorkspaceAppStatusByAppID(ctx,appID)
1999+
}
2000+
19942001
func (q*querier)GetLatestWorkspaceAppStatusesByWorkspaceIDs(ctx context.Context,ids []uuid.UUID) ([]database.WorkspaceAppStatus,error) {
19952002
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceSystem);err!=nil {
19962003
returnnil,err

‎coderd/database/dbauthz/dbauthz_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3801,6 +3801,15 @@ func (s *MethodTestSuite) TestSystemFunctions() {
38013801
LoginType:database.LoginTypeGithub,
38023802
}).Asserts(rbac.ResourceSystem,policy.ActionUpdate).Returns(l)
38033803
}))
3804+
s.Run("GetLatestWorkspaceAppStatusByAppID",s.Subtest(func(db database.Store,check*expects) {
3805+
ws:=dbgen.Workspace(s.T(),db, database.WorkspaceTable{})
3806+
build:=dbgen.WorkspaceBuild(s.T(),db, database.WorkspaceBuild{WorkspaceID:ws.ID,JobID:uuid.New()})
3807+
res:=dbgen.WorkspaceResource(s.T(),db, database.WorkspaceResource{JobID:build.JobID})
3808+
agent:=dbgen.WorkspaceAgent(s.T(),db, database.WorkspaceAgent{ResourceID:res.ID})
3809+
app:=dbgen.WorkspaceApp(s.T(),db, database.WorkspaceApp{AgentID:agent.ID})
3810+
status:=dbgen.WorkspaceAppStatus(s.T(),db, database.WorkspaceAppStatus{WorkspaceID:ws.ID,AgentID:agent.ID,AppID:app.ID})
3811+
check.Args(app.ID).Asserts(rbac.ResourceSystem,policy.ActionRead).Returns(status)
3812+
}))
38043813
s.Run("GetLatestWorkspaceAppStatusesByWorkspaceIDs",s.Subtest(func(db database.Store,check*expects) {
38053814
check.Args([]uuid.UUID{}).Asserts(rbac.ResourceSystem,policy.ActionRead)
38063815
}))

‎coderd/database/dbgen/dbgen.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,24 @@ func WorkspaceAppStat(t testing.TB, db database.Store, orig database.WorkspaceAp
799799
returnscheme
800800
}
801801

802+
funcWorkspaceAppStatus(t testing.TB,db database.Store,orig database.WorkspaceAppStatus) database.WorkspaceAppStatus {
803+
status,err:=db.InsertWorkspaceAppStatus(genCtx, database.InsertWorkspaceAppStatusParams{
804+
ID:takeFirst(orig.ID,uuid.New()),
805+
CreatedAt:takeFirst(orig.CreatedAt,dbtime.Now()),
806+
WorkspaceID:takeFirst(orig.WorkspaceID,uuid.New()),
807+
AgentID:takeFirst(orig.AgentID,uuid.New()),
808+
AppID:takeFirst(orig.AppID,uuid.New()),
809+
Uri: sql.NullString{
810+
String:takeFirst(orig.Uri.String,""),
811+
Valid:takeFirst(orig.Uri.Valid,false),
812+
},
813+
Message:takeFirst(orig.Message,""),
814+
State:takeFirst(orig.State,database.WorkspaceAppStatusStateWorking),
815+
})
816+
require.NoError(t,err,"insert workspace agent status")
817+
returnstatus
818+
}
819+
802820
funcWorkspaceResource(t testing.TB,db database.Store,orig database.WorkspaceResource) database.WorkspaceResource {
803821
resource,err:=db.InsertWorkspaceResource(genCtx, database.InsertWorkspaceResourceParams{
804822
ID:takeFirst(orig.ID,uuid.New()),

‎coderd/database/dbmem/dbmem.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3777,6 +3777,22 @@ func (q *FakeQuerier) GetLatestCryptoKeyByFeature(_ context.Context, feature dat
37773777
returnlatestKey,nil
37783778
}
37793779

3780+
func (q*FakeQuerier)GetLatestWorkspaceAppStatusByAppID(ctx context.Context,appID uuid.UUID) (database.WorkspaceAppStatus,error) {
3781+
q.mutex.RLock()
3782+
deferq.mutex.RUnlock()
3783+
3784+
varcurrent*database.WorkspaceAppStatus=nil
3785+
for_,appStatus:=rangeq.workspaceAppStatuses {
3786+
ifappStatus.AppID==appID&& (current==nil||appStatus.CreatedAt.After(current.CreatedAt)) {
3787+
current=&appStatus
3788+
}
3789+
}
3790+
ifcurrent==nil {
3791+
return database.WorkspaceAppStatus{},sql.ErrNoRows
3792+
}
3793+
return*current,nil
3794+
}
3795+
37803796
func (q*FakeQuerier)GetLatestWorkspaceAppStatusesByWorkspaceIDs(_ context.Context,ids []uuid.UUID) ([]database.WorkspaceAppStatus,error) {
37813797
q.mutex.RLock()
37823798
deferq.mutex.RUnlock()

‎coderd/database/dbmetrics/querymetrics.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/dbmock/dbmock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/workspaceapps.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,7 @@ SELECT DISTINCT ON (workspace_id)
5858
FROM workspace_app_statuses
5959
WHERE workspace_id= ANY(@ids :: uuid[])
6060
ORDER BY workspace_id, created_atDESC;
61+
62+
-- name: GetLatestWorkspaceAppStatusByAppID :one
63+
SELECT*FROM workspace_app_statusesWHERE app_id= $1
64+
ORDER BY created_atDESCLIMIT1;

‎coderd/workspaceagents.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,14 +380,43 @@ func (api *API) patchWorkspaceAgentAppStatus(rw http.ResponseWriter, r *http.Req
380380
return
381381
}
382382

383+
// nolint:gocritic // This is a system restricted operation.
384+
status,err:=api.Database.GetLatestWorkspaceAppStatusByAppID(dbauthz.AsSystemRestricted(ctx),app.ID)
385+
iferr!=nil&&!errors.Is(err,sql.ErrNoRows) {
386+
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
387+
Message:"Internal error fetching workspace app statuses.",
388+
Detail:err.Error(),
389+
})
390+
return
391+
}
392+
// Preserve the existing message, which allows partial updates where we change
393+
// the status but keep the message.
394+
// TODO: What if another status is added while we are doing these checks?
395+
// This would essentially revert the message to the previous one. We could
396+
// maybe do this in the query instead?
397+
ifreq.Message=="" {
398+
req.Message=status.Message
399+
// Only preserve the URI if there was no message. If there is a message and
400+
// a blank URI, we assume the intent is to remove the URI, not preserve it.
401+
ifreq.URI=="" {
402+
req.URI=status.Uri.String
403+
}
404+
}
405+
// Skip duplicate status updates.
406+
newState:=database.WorkspaceAppStatusState(req.State)
407+
ifstatus.State==newState&&status.Message==req.Message&&status.Uri.String==req.URI {
408+
httpapi.Write(ctx,rw,http.StatusOK,nil)
409+
return
410+
}
411+
383412
// nolint:gocritic // This is a system restricted operation.
384413
_,err=api.Database.InsertWorkspaceAppStatus(dbauthz.AsSystemRestricted(ctx), database.InsertWorkspaceAppStatusParams{
385414
ID:uuid.New(),
386415
CreatedAt:dbtime.Now(),
387416
WorkspaceID:workspace.ID,
388417
AgentID:workspaceAgent.ID,
389418
AppID:app.ID,
390-
State:database.WorkspaceAppStatusState(req.State),
419+
State:newState,
391420
Message:req.Message,
392421
Uri: sql.NullString{
393422
String:req.URI,

‎coderd/workspaceagents_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,81 @@ func TestWorkspaceAgentAppStatus(t *testing.T) {
387387
require.False(t,agent.Apps[0].Statuses[0].NeedsUserAttention)
388388
})
389389

390+
t.Run("Patch",func(t*testing.T) {
391+
t.Parallel()
392+
ctx:=testutil.Context(t,testutil.WaitShort)
393+
394+
ws:=dbfake.WorkspaceBuild(t,db, database.WorkspaceTable{
395+
OrganizationID:user.OrganizationID,
396+
OwnerID:user2.ID,
397+
}).WithAgent(func(a []*proto.Agent) []*proto.Agent {
398+
a[0].Apps= []*proto.App{
399+
{
400+
Slug:"vscode",
401+
},
402+
}
403+
returna
404+
}).Do()
405+
406+
agentClient:=agentsdk.New(client.URL)
407+
agentClient.SetSessionToken(ws.AgentToken)
408+
409+
err:=agentClient.PatchAppStatus(ctx, agentsdk.PatchAppStatus{
410+
AppSlug:"vscode",
411+
Message:"testing",
412+
URI:"https://example.com",
413+
State:codersdk.WorkspaceAppStatusStateComplete,
414+
})
415+
require.NoError(t,err)
416+
417+
// Duplicate should be a no-op.
418+
err=agentClient.PatchAppStatus(ctx, agentsdk.PatchAppStatus{
419+
AppSlug:"vscode",
420+
Message:"testing",
421+
URI:"https://example.com",
422+
State:codersdk.WorkspaceAppStatusStateComplete,
423+
})
424+
require.NoError(t,err)
425+
426+
// If no message, both the old message and URI are preserved, and this ends
427+
// up being a duplicate as well.
428+
err=agentClient.PatchAppStatus(ctx, agentsdk.PatchAppStatus{
429+
AppSlug:"vscode",
430+
State:codersdk.WorkspaceAppStatusStateComplete,
431+
})
432+
require.NoError(t,err)
433+
434+
// Same, but the status updated so it will not be a duplicate.
435+
err=agentClient.PatchAppStatus(ctx, agentsdk.PatchAppStatus{
436+
AppSlug:"vscode",
437+
State:codersdk.WorkspaceAppStatusStateWorking,
438+
})
439+
require.NoError(t,err)
440+
441+
// Message update, so nothing is preserved.
442+
err=agentClient.PatchAppStatus(ctx, agentsdk.PatchAppStatus{
443+
AppSlug:"vscode",
444+
Message:"updated",
445+
State:codersdk.WorkspaceAppStatusStateWorking,
446+
})
447+
require.NoError(t,err)
448+
449+
workspace,err:=client.Workspace(ctx,ws.Workspace.ID)
450+
require.NoError(t,err)
451+
agent,err:=client.WorkspaceAgent(ctx,workspace.LatestBuild.Resources[0].Agents[0].ID)
452+
require.NoError(t,err)
453+
require.Len(t,agent.Apps[0].Statuses,3)
454+
require.Equal(t,agent.Apps[0].Statuses[0].State,codersdk.WorkspaceAppStatusStateComplete)
455+
require.Equal(t,agent.Apps[0].Statuses[0].Message,"testing")
456+
require.Equal(t,agent.Apps[0].Statuses[0].URI,"https://example.com")
457+
require.Equal(t,agent.Apps[0].Statuses[1].State,codersdk.WorkspaceAppStatusStateWorking)
458+
require.Equal(t,agent.Apps[0].Statuses[1].Message,"testing")
459+
require.Equal(t,agent.Apps[0].Statuses[1].URI,"https://example.com")
460+
require.Equal(t,agent.Apps[0].Statuses[2].State,codersdk.WorkspaceAppStatusStateWorking)
461+
require.Equal(t,agent.Apps[0].Statuses[2].Message,"updated")
462+
require.Equal(t,agent.Apps[0].Statuses[2].URI,"")
463+
})
464+
390465
t.Run("FailUnknownApp",func(t*testing.T) {
391466
t.Parallel()
392467
ctx:=testutil.Context(t,testutil.WaitShort)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp