Skip to content

Commit 5d57819

Browse files
akosyakovroboquat
authored andcommitted
[supervisor] prevent slow clients to stale tasks in headless workspaces
1 parent 7a0529e commit 5d57819

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

components/supervisor/pkg/supervisor/tasks.go

+8-9
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,8 @@ func (tm *tasksManager) Run(ctx context.Context, wg *sync.WaitGroup, successChan
258258
}
259259
}
260260
}
261-
var readTimeout time.Duration
262-
if !tm.config.isHeadless() {
263-
readTimeout = 5 * time.Second
264-
}
265261
resp, err := tm.terminalService.OpenWithOptions(ctx, openRequest, terminal.TermOptions{
266-
ReadTimeout: readTimeout,
262+
ReadTimeout: 5 * time.Second,
267263
Title: t.title,
268264
})
269265
if err != nil {
@@ -413,15 +409,18 @@ func prebuildLogFileName(task *task, storeLocation string) string {
413409
return logs.PrebuildLogFileName(storeLocation, task.Id)
414410
}
415411

416-
func (tm *tasksManager) watch(task *task, terminal *terminal.Term) {
412+
func (tm *tasksManager) watch(task *task, term *terminal.Term) {
417413
if !tm.config.isHeadless() {
418414
return
419415
}
420416

421417
var (
422-
terminalLog = log.WithField("pid", terminal.Command.Process.Pid)
423-
stdout = terminal.Stdout.Listen()
424-
start = time.Now()
418+
terminalLog = log.WithField("pid", term.Command.Process.Pid)
419+
stdout = term.Stdout.ListenWithOptions(terminal.TermListenOptions{
420+
// ensure logging of entire task output
421+
ReadTimeout: terminal.NoTimeout,
422+
})
423+
start = time.Now()
425424
)
426425
go func() {
427426
defer stdout.Close()

components/supervisor/pkg/terminal/terminal.go

+25-3
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ func newTerm(alias string, pty *os.File, cmd *exec.Cmd, options TermOptions) (*T
204204

205205
timeout := options.ReadTimeout
206206
if timeout == 0 {
207-
timeout = 1<<63 - 1
207+
timeout = NoTimeout
208208
}
209209
res := &Term{
210210
PTY: pty,
@@ -244,6 +244,9 @@ func newTerm(alias string, pty *os.File, cmd *exec.Cmd, options TermOptions) (*T
244244
return res, nil
245245
}
246246

247+
// NoTimeout means that listener can block read forever
248+
var NoTimeout time.Duration = 1<<63 - 1
249+
247250
// TermOptions is a pseudo-terminal configuration.
248251
type TermOptions struct {
249252
// timeout after which a listener is dropped. Use 0 for no timeout.
@@ -375,6 +378,7 @@ var (
375378

376379
type multiWriterListener struct {
377380
io.Reader
381+
timeout time.Duration
378382

379383
closed bool
380384
once sync.Once
@@ -413,22 +417,40 @@ func (closedTerminalListener) Read(p []byte) (n int, err error) {
413417

414418
var closedListener = io.NopCloser(closedTerminalListener{})
415419

420+
// TermListenOptions is a configuration to listen to the pseudo-terminal .
421+
type TermListenOptions struct {
422+
// timeout after which a listener is dropped. Use 0 for default timeout.
423+
ReadTimeout time.Duration
424+
}
425+
416426
// Listen listens in on the multi-writer stream.
417427
func (mw *multiWriter) Listen() io.ReadCloser {
428+
return mw.ListenWithOptions(TermListenOptions{
429+
ReadTimeout: 0,
430+
})
431+
}
432+
433+
// Listen listens in on the multi-writer stream with given options.
434+
func (mw *multiWriter) ListenWithOptions(options TermListenOptions) io.ReadCloser {
418435
mw.mu.Lock()
419436
defer mw.mu.Unlock()
420437

421438
if mw.closed {
422439
return closedListener
423440
}
424441

442+
timeout := options.ReadTimeout
443+
if timeout == 0 {
444+
timeout = mw.timeout
445+
}
425446
r, w := io.Pipe()
426447
cchan, done, closeChan := make(chan []byte), make(chan struct{}, 1), make(chan struct{}, 1)
427448
res := &multiWriterListener{
428449
Reader: r,
429450
cchan: cchan,
430451
done: done,
431452
closeChan: closeChan,
453+
timeout: timeout,
432454
}
433455

434456
recording := mw.recorder.Bytes()
@@ -489,13 +511,13 @@ func (mw *multiWriter) Write(p []byte) (n int, err error) {
489511

490512
select {
491513
case lstr.cchan <- p:
492-
case <-time.After(mw.timeout):
514+
case <-time.After(lstr.timeout):
493515
lstr.CloseWithError(ErrReadTimeout)
494516
}
495517

496518
select {
497519
case <-lstr.done:
498-
case <-time.After(mw.timeout):
520+
case <-time.After(lstr.timeout):
499521
lstr.CloseWithError(ErrReadTimeout)
500522
}
501523
}

0 commit comments

Comments
 (0)