| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- package executor
- import (
- "context"
- "os"
- "sync"
- "time"
- log "github.com/sirupsen/logrus"
- )
- // timeoutContext is a custom context that kills the process group when cancelled due to timeout.
- type timeoutContext struct {
- context.Context
- cancel context.CancelFunc
- process *os.Process
- executor *Executor
- processMu sync.Mutex
- }
- // newTimeoutContext creates a context that will kill the process group when the timeout expires.
- func newTimeoutContext(parent context.Context, timeout time.Duration, executor *Executor) (*timeoutContext, context.CancelFunc) {
- ctx, cancel := context.WithTimeout(parent, timeout)
- tc := &timeoutContext{
- Context: ctx,
- cancel: cancel,
- executor: executor,
- }
- // Start a goroutine that kills the process group when the context is cancelled
- go func() {
- <-ctx.Done()
- if ctx.Err() == context.DeadlineExceeded {
- tc.processMu.Lock()
- process := tc.process
- tc.processMu.Unlock()
- if process != nil {
- logEntry := &InternalLogEntry{Process: process}
- if err := executor.Kill(logEntry); err != nil {
- log.WithFields(log.Fields{
- "error": err,
- }).Warnf("Failed to kill process group on timeout")
- }
- }
- }
- }()
- return tc, cancel
- }
- func (tc *timeoutContext) setProcess(process *os.Process) {
- tc.processMu.Lock()
- tc.process = process
- tc.processMu.Unlock()
- // If deadline already expired before process was set, kill now
- if tc.Context.Err() == context.DeadlineExceeded && process != nil {
- logEntry := &InternalLogEntry{Process: process}
- if err := tc.executor.Kill(logEntry); err != nil {
- log.WithFields(log.Fields{
- "error": err,
- }).Warnf("Failed to kill process group on timeout (late registration)")
- }
- }
- }
|