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

Commit552e9fe

Browse files
authored
fix: avoid returning 500 on apps when workspace stopped (#11656)
1 parent1be119b commit552e9fe

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

‎coderd/workspaceapps/apptest/apptest.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"golang.org/x/xerrors"
2727

2828
"github.com/coder/coder/v2/coderd/coderdtest"
29+
"github.com/coder/coder/v2/coderd/database"
2930
"github.com/coder/coder/v2/coderd/rbac"
3031
"github.com/coder/coder/v2/coderd/workspaceapps"
3132
"github.com/coder/coder/v2/codersdk"
@@ -1484,6 +1485,24 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
14841485
assert.Equal(t,"test-app-owner",stats[0].SlugOrPort)
14851486
assert.Equal(t,1,stats[0].Requests)
14861487
})
1488+
1489+
t.Run("WorkspaceOffline",func(t*testing.T) {
1490+
t.Parallel()
1491+
1492+
appDetails:=setupProxyTest(t,nil)
1493+
1494+
ctx,cancel:=context.WithTimeout(context.Background(),testutil.WaitLong)
1495+
defercancel()
1496+
1497+
_=coderdtest.MustTransitionWorkspace(t,appDetails.SDKClient,appDetails.Workspace.ID,database.WorkspaceTransitionStart,database.WorkspaceTransitionStop)
1498+
1499+
u:=appDetails.PathAppURL(appDetails.Apps.Owner)
1500+
resp,err:=appDetails.AppClient(t).Request(ctx,http.MethodGet,u.String(),nil)
1501+
require.NoError(t,err)
1502+
_=resp.Body.Close()
1503+
require.Equal(t,http.StatusBadRequest,resp.StatusCode)
1504+
require.Equal(t,"text/html; charset=utf-8",resp.Header.Get("Content-Type"))
1505+
})
14871506
}
14881507

14891508
typefakeStatsReporterstruct {

‎coderd/workspaceapps/db.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
103103
ifxerrors.Is(err,sql.ErrNoRows) {
104104
WriteWorkspaceApp404(p.Logger,p.DashboardURL,rw,r,&appReq,nil,err.Error())
105105
returnnil,"",false
106+
}elseifxerrors.Is(err,errWorkspaceStopped) {
107+
WriteWorkspaceOffline(p.Logger,p.DashboardURL,rw,r,&appReq)
108+
returnnil,"",false
106109
}elseiferr!=nil {
107110
WriteWorkspaceApp500(p.Logger,p.DashboardURL,rw,r,&appReq,err,"get app details from database")
108111
returnnil,"",false

‎coderd/workspaceapps/errors.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package workspaceapps
22

33
import (
4+
"fmt"
45
"net/http"
56
"net/url"
67

78
"cdr.dev/slog"
9+
"github.com/coder/coder/v2/codersdk"
810
"github.com/coder/coder/v2/site"
911
)
1012

@@ -90,3 +92,28 @@ func WriteWorkspaceAppOffline(log slog.Logger, accessURL *url.URL, rw http.Respo
9092
DashboardURL:accessURL.String(),
9193
})
9294
}
95+
96+
// WriteWorkspaceOffline writes a HTML 400 error page for a workspace app. If
97+
// appReq is not nil, it will be used to log the request details at debug level.
98+
funcWriteWorkspaceOffline(log slog.Logger,accessURL*url.URL,rw http.ResponseWriter,r*http.Request,appReq*Request) {
99+
ifappReq!=nil {
100+
slog.Helper()
101+
log.Debug(r.Context(),
102+
"workspace app unavailable: workspace stopped",
103+
slog.F("username_or_id",appReq.UsernameOrID),
104+
slog.F("workspace_and_agent",appReq.WorkspaceAndAgent),
105+
slog.F("workspace_name_or_id",appReq.WorkspaceNameOrID),
106+
slog.F("agent_name_or_id",appReq.AgentNameOrID),
107+
slog.F("app_slug_or_port",appReq.AppSlugOrPort),
108+
slog.F("hostname_prefix",appReq.Prefix),
109+
)
110+
}
111+
112+
site.RenderStaticErrorPage(rw,r, site.ErrorPageData{
113+
Status:http.StatusBadRequest,
114+
Title:"Workspace Offline",
115+
Description:fmt.Sprintf("Last workspace transition was to the %q state. Start the workspace to access its applications.",codersdk.WorkspaceTransitionStop),
116+
RetryEnabled:false,
117+
DashboardURL:accessURL.String(),
118+
})
119+
}

‎coderd/workspaceapps/request.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"github.com/coder/coder/v2/codersdk"
1818
)
1919

20+
varerrWorkspaceStopped=xerrors.New("stopped workspace")
21+
2022
typeAccessMethodstring
2123

2224
const (
@@ -260,10 +262,17 @@ func (r Request) getDatabase(ctx context.Context, db database.Store) (*databaseR
260262
iferr!=nil {
261263
returnnil,xerrors.Errorf("get workspace agents: %w",err)
262264
}
265+
build,err:=db.GetLatestWorkspaceBuildByWorkspaceID(ctx,workspace.ID)
266+
iferr!=nil {
267+
returnnil,xerrors.Errorf("get latest workspace build: %w",err)
268+
}
269+
ifbuild.Transition==database.WorkspaceTransitionStop {
270+
returnnil,errWorkspaceStopped
271+
}
263272
iflen(agents)==0 {
264273
// TODO(@deansheather): return a 404 if there are no agents in the
265274
// workspace, requires a different error type.
266-
returnnil,xerrors.New("no agents in workspace")
275+
returnnil,xerrors.Errorf("no agents in workspace: %w",sql.ErrNoRows)
267276
}
268277

269278
// Get workspace apps.

‎site/src/pages/TerminalPage/TerminalPage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ const TerminalPage: FC = () => {
191191
return;
192192
}elseif(!workspaceAgent){
193193
terminal.writeln(
194-
Language.workspaceAgentErrorMessagePrefix+"no agent found with ID",
194+
Language.workspaceAgentErrorMessagePrefix+
195+
"no agent found with ID, is the workspace started?",
195196
);
196197
return;
197198
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp