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

Commit022372d

Browse files
authored
feat(healthcheck): add websocket report (#7689)
1 parent77b0ca0 commit022372d

File tree

11 files changed

+467
-30
lines changed

11 files changed

+467
-30
lines changed

‎coderd/apidoc/docs.go

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

‎coderd/apidoc/swagger.json

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

‎coderd/coderd.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ type Options struct {
129129
// AppSecurityKey is the crypto key used to sign and encrypt tokens related to
130130
// workspace applications. It consists of both a signing and encryption key.
131131
AppSecurityKey workspaceapps.SecurityKey
132-
HealthcheckFuncfunc(ctx context.Context) (*healthcheck.Report,error)
132+
HealthcheckFuncfunc(ctx context.Context,apiKeystring) (*healthcheck.Report,error)
133133
HealthcheckTimeout time.Duration
134134
HealthcheckRefresh time.Duration
135135

@@ -256,10 +256,11 @@ func New(options *Options) *API {
256256
options.TemplateScheduleStore.Store(&v)
257257
}
258258
ifoptions.HealthcheckFunc==nil {
259-
options.HealthcheckFunc=func(ctx context.Context) (*healthcheck.Report,error) {
259+
options.HealthcheckFunc=func(ctx context.Context,apiKeystring) (*healthcheck.Report,error) {
260260
returnhealthcheck.Run(ctx,&healthcheck.ReportOptions{
261261
AccessURL:options.AccessURL,
262262
DERPMap:options.DERPMap.Clone(),
263+
APIKey:apiKey,
263264
})
264265
}
265266
}
@@ -787,6 +788,7 @@ func New(options *Options) *API {
787788

788789
r.Get("/coordinator",api.debugCoordinator)
789790
r.Get("/health",api.debugDeploymentHealth)
791+
r.Get("/ws", (&healthcheck.WebsocketEchoServer{}).ServeHTTP)
790792
})
791793
})
792794

@@ -874,6 +876,7 @@ type API struct {
874876
Experiments codersdk.Experiments
875877

876878
healthCheckGroup*singleflight.Group[string,*healthcheck.Report]
879+
healthCheckCache atomic.Pointer[healthcheck.Report]
877880
}
878881

879882
// Close waits for all WebSocket connections to drain before returning.

‎coderd/coderdtest/coderdtest.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ type Options struct {
107107
TrialGeneratorfunc(context.Context,string)error
108108
TemplateScheduleStore schedule.TemplateScheduleStore
109109

110-
HealthcheckFuncfunc(ctx context.Context) (*healthcheck.Report,error)
110+
HealthcheckFuncfunc(ctx context.Context,apiKeystring) (*healthcheck.Report,error)
111111
HealthcheckTimeout time.Duration
112112
HealthcheckRefresh time.Duration
113113

‎coderd/debug.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/coder/coder/coderd/healthcheck"
99
"github.com/coder/coder/coderd/httpapi"
10+
"github.com/coder/coder/coderd/httpmw"
1011
"github.com/coder/coder/codersdk"
1112
)
1213

@@ -29,11 +30,28 @@ func (api *API) debugCoordinator(rw http.ResponseWriter, r *http.Request) {
2930
// @Success 200 {object} healthcheck.Report
3031
// @Router /debug/health [get]
3132
func (api*API)debugDeploymentHealth(rw http.ResponseWriter,r*http.Request) {
33+
apiKey:=httpmw.APITokenFromRequest(r)
3234
ctx,cancel:=context.WithTimeout(r.Context(),api.HealthcheckTimeout)
3335
defercancel()
3436

37+
// Get cached report if it exists.
38+
ifreport:=api.healthCheckCache.Load();report!=nil {
39+
iftime.Since(report.Time)<api.HealthcheckRefresh {
40+
httpapi.Write(ctx,rw,http.StatusOK,report)
41+
return
42+
}
43+
}
44+
3545
resChan:=api.healthCheckGroup.DoChan("",func() (*healthcheck.Report,error) {
36-
returnapi.HealthcheckFunc(ctx)
46+
// Create a new context not tied to the request.
47+
ctx,cancel:=context.WithTimeout(context.Background(),api.HealthcheckTimeout)
48+
defercancel()
49+
50+
report,err:=api.HealthcheckFunc(ctx,apiKey)
51+
iferr==nil {
52+
api.healthCheckCache.Store(report)
53+
}
54+
returnreport,err
3755
})
3856

3957
select {
@@ -43,13 +61,19 @@ func (api *API) debugDeploymentHealth(rw http.ResponseWriter, r *http.Request) {
4361
})
4462
return
4563
caseres:=<-resChan:
46-
iftime.Since(res.Val.Time)>api.HealthcheckRefresh {
47-
api.healthCheckGroup.Forget("")
48-
api.debugDeploymentHealth(rw,r)
49-
return
50-
}
51-
5264
httpapi.Write(ctx,rw,http.StatusOK,res.Val)
5365
return
5466
}
5567
}
68+
69+
// For some reason the swagger docs need to be attached to a function.
70+
//
71+
// @Summary Debug Info Websocket Test
72+
// @ID debug-info-websocket-test
73+
// @Security CoderSessionToken
74+
// @Produce json
75+
// @Tags Debug
76+
// @Success 201 {object} codersdk.Response
77+
// @Router /debug/ws [get]
78+
// @x-apidocgen {"skip": true}
79+
func_debugws(http.ResponseWriter,*http.Request) {}//nolint:unused

‎coderd/debug_test.go

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,48 @@ import (
77
"testing"
88
"time"
99

10+
"github.com/stretchr/testify/assert"
1011
"github.com/stretchr/testify/require"
1112

1213
"github.com/coder/coder/coderd/coderdtest"
1314
"github.com/coder/coder/coderd/healthcheck"
1415
"github.com/coder/coder/testutil"
1516
)
1617

17-
funcTestDebug(t*testing.T) {
18+
funcTestDebugHealth(t*testing.T) {
1819
t.Parallel()
19-
t.Run("Health/OK",func(t*testing.T) {
20+
t.Run("OK",func(t*testing.T) {
2021
t.Parallel()
2122

2223
var (
23-
ctx,cancel=context.WithTimeout(context.Background(),testutil.WaitShort)
24-
client=coderdtest.New(t,&coderdtest.Options{
25-
HealthcheckFunc:func(context.Context) (*healthcheck.Report,error) {
24+
ctx,cancel=context.WithTimeout(context.Background(),testutil.WaitShort)
25+
sessionTokenstring
26+
client=coderdtest.New(t,&coderdtest.Options{
27+
HealthcheckFunc:func(_ context.Context,apiKeystring) (*healthcheck.Report,error) {
28+
assert.Equal(t,sessionToken,apiKey)
2629
return&healthcheck.Report{},nil
2730
},
2831
})
2932
_=coderdtest.CreateFirstUser(t,client)
3033
)
3134
defercancel()
3235

36+
sessionToken=client.SessionToken()
3337
res,err:=client.Request(ctx,"GET","/debug/health",nil)
3438
require.NoError(t,err)
3539
deferres.Body.Close()
3640
_,_=io.ReadAll(res.Body)
3741
require.Equal(t,http.StatusOK,res.StatusCode)
3842
})
3943

40-
t.Run("Health/Timeout",func(t*testing.T) {
44+
t.Run("Timeout",func(t*testing.T) {
4145
t.Parallel()
4246

4347
var (
4448
ctx,cancel=context.WithTimeout(context.Background(),testutil.WaitShort)
4549
client=coderdtest.New(t,&coderdtest.Options{
4650
HealthcheckTimeout:time.Microsecond,
47-
HealthcheckFunc:func(context.Context) (*healthcheck.Report,error) {
51+
HealthcheckFunc:func(context.Context,string) (*healthcheck.Report,error) {
4852
t:=time.NewTimer(time.Second)
4953
defert.Stop()
5054

@@ -66,4 +70,48 @@ func TestDebug(t *testing.T) {
6670
_,_=io.ReadAll(res.Body)
6771
require.Equal(t,http.StatusNotFound,res.StatusCode)
6872
})
73+
74+
t.Run("Deduplicated",func(t*testing.T) {
75+
t.Parallel()
76+
77+
var (
78+
ctx,cancel=context.WithTimeout(context.Background(),testutil.WaitShort)
79+
callsint
80+
client=coderdtest.New(t,&coderdtest.Options{
81+
HealthcheckRefresh:time.Hour,
82+
HealthcheckTimeout:time.Hour,
83+
HealthcheckFunc:func(context.Context,string) (*healthcheck.Report,error) {
84+
calls++
85+
return&healthcheck.Report{
86+
Time:time.Now(),
87+
},nil
88+
},
89+
})
90+
_=coderdtest.CreateFirstUser(t,client)
91+
)
92+
defercancel()
93+
94+
res,err:=client.Request(ctx,"GET","/api/v2/debug/health",nil)
95+
require.NoError(t,err)
96+
deferres.Body.Close()
97+
_,_=io.ReadAll(res.Body)
98+
99+
require.Equal(t,http.StatusOK,res.StatusCode)
100+
101+
res,err=client.Request(ctx,"GET","/api/v2/debug/health",nil)
102+
require.NoError(t,err)
103+
deferres.Body.Close()
104+
_,_=io.ReadAll(res.Body)
105+
106+
require.Equal(t,http.StatusOK,res.StatusCode)
107+
require.Equal(t,1,calls)
108+
})
109+
}
110+
111+
funcTestDebugWebsocket(t*testing.T) {
112+
t.Parallel()
113+
114+
t.Run("OK",func(t*testing.T) {
115+
t.Parallel()
116+
})
69117
}

‎coderd/healthcheck/healthcheck.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,15 @@ type Report struct {
1919

2020
DERPDERPReport`json:"derp"`
2121
AccessURLAccessURLReport`json:"access_url"`
22-
23-
// TODO:
24-
// Websocket WebsocketReport `json:"websocket"`
22+
WebsocketWebsocketReport`json:"websocket"`
2523
}
2624

2725
typeReportOptionsstruct {
2826
// TODO: support getting this over HTTP?
2927
DERPMap*tailcfg.DERPMap
3028
AccessURL*url.URL
3129
Client*http.Client
30+
APIKeystring
3231
}
3332

3433
funcRun(ctx context.Context,opts*ReportOptions) (*Report,error) {
@@ -65,11 +64,19 @@ func Run(ctx context.Context, opts *ReportOptions) (*Report, error) {
6564
})
6665
}()
6766

68-
// wg.Add(1)
69-
// go func() {
70-
// defer wg.Done()
71-
// report.Websocket.Run(ctx, opts.AccessURL)
72-
// }()
67+
wg.Add(1)
68+
gofunc() {
69+
deferwg.Done()
70+
deferfunc() {
71+
iferr:=recover();err!=nil {
72+
report.Websocket.Error=xerrors.Errorf("%v",err)
73+
}
74+
}()
75+
report.Websocket.Run(ctx,&WebsocketReportOptions{
76+
APIKey:opts.APIKey,
77+
AccessURL:opts.AccessURL,
78+
})
79+
}()
7380

7481
wg.Wait()
7582
report.Time=time.Now()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp