Skip to content

Commit 45070dd

Browse files
authored
[supervisor] Don't emit DeadlineExceeded if client closes connection (feature flag: supervisor_terminal_no_deadline_exceeded) (#20851)
1 parent f35a251 commit 45070dd

File tree

4 files changed

+61
-7
lines changed

4 files changed

+61
-7
lines changed

components/supervisor/pkg/supervisor/supervisor.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"strconv"
3030
"strings"
3131
"sync"
32+
"sync/atomic"
3233
"syscall"
3334
"time"
3435

@@ -336,9 +337,10 @@ func Run(options ...RunOption) {
336337
}
337338
}
338339

340+
terminalNoDeadlineExceeded := watchTerminalNoDeadlineExceeded(ctx, exps, host)
339341
willShutdownCtx, fireWillShutdown := context.WithCancel(ctx)
340342
termMux := terminal.NewMux()
341-
termMuxSrv := terminal.NewMuxTerminalService(termMux)
343+
termMuxSrv := terminal.NewMuxTerminalService(termMux, terminalNoDeadlineExceeded)
342344
termMuxSrv.DefaultWorkdir = cfg.RepoRoot
343345
if cfg.WorkspaceRoot != "" {
344346
termMuxSrv.DefaultWorkdirProvider = func() string {
@@ -582,6 +584,36 @@ func getIDENotReadyShutdownDuration(ctx context.Context, exps experiments.Client
582584
}
583585
}
584586

587+
func watchTerminalNoDeadlineExceeded(ctx context.Context, exps experiments.Client, gitpodHost string) *atomic.Bool {
588+
newBool := func(v bool) *atomic.Bool {
589+
r := atomic.Bool{}
590+
r.Store(v)
591+
return &r
592+
}
593+
if exps == nil {
594+
return newBool(false)
595+
}
596+
597+
value := exps.GetBoolValue(ctx, "supervisor_terminal_no_deadline_exceeded", false, experiments.Attributes{GitpodHost: gitpodHost})
598+
result := newBool(value)
599+
600+
go (func() {
601+
t := time.NewTicker(30 * time.Second)
602+
603+
for {
604+
select {
605+
case <-ctx.Done():
606+
return
607+
case <-t.C:
608+
value := exps.GetBoolValue(ctx, "supervisor_terminal_no_deadline_exceeded", false, experiments.Attributes{GitpodHost: gitpodHost})
609+
result.Store(value)
610+
}
611+
}
612+
})()
613+
614+
return result
615+
}
616+
585617
func isShallowRepository(rootDir string) bool {
586618
cmd := runAsGitpodUser(exec.Command("git", "rev-parse", "--is-shallow-repository"))
587619
cmd.Dir = rootDir

components/supervisor/pkg/supervisor/tasks_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os"
1111
"strconv"
1212
"sync"
13+
"sync/atomic"
1314
"testing"
1415

1516
"github.com/google/go-cmp/cmp"
@@ -21,6 +22,12 @@ import (
2122
"github.com/gitpod-io/gitpod/supervisor/pkg/terminal"
2223
)
2324

25+
func newBool(b bool) *atomic.Bool {
26+
result := atomic.Bool{}
27+
result.Store(b)
28+
return &result
29+
}
30+
2431
var (
2532
skipCommand = "echo \"skip\""
2633
failCommand = "exit 1"
@@ -216,7 +223,7 @@ func TestTaskManager(t *testing.T) {
216223
}
217224

218225
var (
219-
terminalService = terminal.NewMuxTerminalService(terminal.NewMux())
226+
terminalService = terminal.NewMuxTerminalService(terminal.NewMux(), newBool(true))
220227
contentState = NewInMemoryContentState("")
221228
reporter = testHeadlessTaskProgressReporter{}
222229
taskManager = newTasksManager(&Config{

components/supervisor/pkg/terminal/service.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os"
1212
"os/exec"
1313
"path/filepath"
14+
"sync/atomic"
1415
"syscall"
1516
"time"
1617

@@ -26,7 +27,7 @@ import (
2627
)
2728

2829
// NewMuxTerminalService creates a new terminal service.
29-
func NewMuxTerminalService(m *Mux) *MuxTerminalService {
30+
func NewMuxTerminalService(m *Mux, terminalNoDeadlineExceeded *atomic.Bool) *MuxTerminalService {
3031
shell := os.Getenv("SHELL")
3132
if shell == "" {
3233
shell = "/bin/bash"
@@ -36,6 +37,8 @@ func NewMuxTerminalService(m *Mux) *MuxTerminalService {
3637
DefaultWorkdir: "/workspace",
3738
DefaultShell: shell,
3839
Env: os.Environ(),
40+
41+
terminalNoDeadlineExceeded: terminalNoDeadlineExceeded,
3942
}
4043
}
4144

@@ -53,6 +56,8 @@ type MuxTerminalService struct {
5356
DefaultCreds *syscall.Credential
5457
DefaultAmbientCaps []uintptr
5558

59+
terminalNoDeadlineExceeded *atomic.Bool
60+
5661
api.UnimplementedTerminalServiceServer
5762
}
5863

@@ -286,6 +291,9 @@ func (srv *MuxTerminalService) Listen(req *api.ListenTerminalRequest, resp api.T
286291
err = resp.Send(message)
287292
case err = <-errchan:
288293
case <-resp.Context().Done():
294+
if srv.terminalNoDeadlineExceeded.Load() {
295+
return nil
296+
}
289297
return status.Error(codes.DeadlineExceeded, resp.Context().Err().Error())
290298
}
291299
if err == io.EOF {

components/supervisor/pkg/terminal/terminal_test.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os"
1212
"os/exec"
1313
"strings"
14+
"sync/atomic"
1415
"testing"
1516
"time"
1617

@@ -21,6 +22,12 @@ import (
2122
"github.com/gitpod-io/gitpod/supervisor/api"
2223
)
2324

25+
func newBool(b bool) *atomic.Bool {
26+
result := atomic.Bool{}
27+
result.Store(b)
28+
return &result
29+
}
30+
2431
func TestTitle(t *testing.T) {
2532
t.Skip("skipping flakey tests")
2633

@@ -59,7 +66,7 @@ func TestTitle(t *testing.T) {
5966
}
6067
defer os.RemoveAll(tmpWorkdir)
6168

62-
terminalService := NewMuxTerminalService(mux)
69+
terminalService := NewMuxTerminalService(mux, newBool(true))
6370
terminalService.DefaultWorkdir = tmpWorkdir
6471

6572
term, err := terminalService.OpenWithOptions(ctx, &api.OpenTerminalRequest{}, TermOptions{
@@ -197,7 +204,7 @@ func TestAnnotations(t *testing.T) {
197204
mux := NewMux()
198205
defer mux.Close(ctx)
199206

200-
terminalService := NewMuxTerminalService(mux)
207+
terminalService := NewMuxTerminalService(mux, newBool(true))
201208
var err error
202209
if test.Opts == nil {
203210
_, err = terminalService.Open(ctx, test.Req)
@@ -248,7 +255,7 @@ func TestTerminals(t *testing.T) {
248255
}
249256
for _, test := range tests {
250257
t.Run(test.Desc, func(t *testing.T) {
251-
terminalService := NewMuxTerminalService(NewMux())
258+
terminalService := NewMuxTerminalService(NewMux(), newBool(true))
252259
resp, err := terminalService.Open(context.Background(), &api.OpenTerminalRequest{})
253260
if err != nil {
254261
t.Fatal(err)
@@ -329,7 +336,7 @@ func TestWorkDirProvider(t *testing.T) {
329336
mux := NewMux()
330337
defer mux.Close(ctx)
331338

332-
terminalService := NewMuxTerminalService(mux)
339+
terminalService := NewMuxTerminalService(mux, newBool(true))
333340

334341
type AssertWorkDirTest struct {
335342
expectedWorkDir string

0 commit comments

Comments
 (0)