diff --git a/cmd/toolsrv/internal/server/proc.go b/cmd/toolsrv/internal/server/proc.go index d48bfbd..af27d8b 100644 --- a/cmd/toolsrv/internal/server/proc.go +++ b/cmd/toolsrv/internal/server/proc.go @@ -518,7 +518,10 @@ func (st *State) DismissProc(pid int) bool { return true } -const procGCTTL = 10 * time.Minute +const ( + procGCTTL = 10 * time.Minute + procOutputLimit = 10 * 1024 * 1024 +) // StartProcGC runs a background goroutine that removes exited procs // whose output has been read and whose LastRead is older than procGCTTL. @@ -545,8 +548,9 @@ func (st *State) gcProcs() { p.mu.Lock() exited := p.Exited lastRead := p.LastRead + endTime := p.EndTime p.mu.Unlock() - if exited && !lastRead.IsZero() && now.Sub(lastRead) >= procGCTTL { + if exited && ((!lastRead.IsZero() && now.Sub(lastRead) >= procGCTTL) || (!endTime.IsZero() && now.Sub(endTime) >= procGCTTL)) { delete(st.procs, pid) } } @@ -697,7 +701,15 @@ type procWriter struct { func (pw *procWriter) Write(p []byte) (int, error) { pw.proc.mu.Lock() defer pw.proc.mu.Unlock() - return pw.proc.output.Write(p) + remaining := procOutputLimit - pw.proc.output.Len() + if remaining > 0 { + if len(p) > remaining { + _, _ = pw.proc.output.Write(p[:remaining]) + } else { + _, _ = pw.proc.output.Write(p) + } + } + return len(p), nil } // --- Proc Methods --- diff --git a/cmd/toolsrv/internal/server/proc_test.go b/cmd/toolsrv/internal/server/proc_test.go index 4281c5c..b5f6f32 100644 --- a/cmd/toolsrv/internal/server/proc_test.go +++ b/cmd/toolsrv/internal/server/proc_test.go @@ -235,9 +235,10 @@ func TestGcProcs(t *testing.T) { } // Add a proc that's exited but never read st.procs[2] = &Proc{ - ID: 2, - Exited: true, - done: make(chan struct{}), + ID: 2, + Exited: true, + EndTime: time.Now().Add(-20 * time.Minute), + done: make(chan struct{}), } // Add a proc that's exited and recently read st.procs[3] = &Proc{ @@ -263,7 +264,7 @@ func TestGcProcs(t *testing.T) { if _, ok := st.procs[1]; ok { t.Error("proc 1 should have been GC'd (exited, read >10min ago)") } - if _, ok := st.procs[2]; !ok { + if _, ok := st.procs[2]; ok { t.Error("proc 2 should NOT be GC'd (never read)") } if _, ok := st.procs[3]; !ok {