timeout_context.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package executor
  2. import (
  3. "context"
  4. "os"
  5. "sync"
  6. "time"
  7. "errors"
  8. log "github.com/sirupsen/logrus"
  9. )
  10. // timeoutContext is a custom context that kills the process group when cancelled due to timeout.
  11. type timeoutContext struct {
  12. context.Context
  13. cancel context.CancelFunc
  14. process *os.Process
  15. executor *Executor
  16. processMu sync.Mutex
  17. }
  18. // newTimeoutContext creates a context that will kill the process group when the timeout expires.
  19. func newTimeoutContext(parent context.Context, timeout time.Duration, executor *Executor) (*timeoutContext, context.CancelFunc) {
  20. ctx, cancel := context.WithTimeout(parent, timeout)
  21. tc := &timeoutContext{
  22. Context: ctx,
  23. cancel: cancel,
  24. executor: executor,
  25. }
  26. // Start a goroutine that kills the process group when the context is cancelled
  27. go func() {
  28. <-ctx.Done()
  29. if ctx.Err() == context.DeadlineExceeded {
  30. tc.processMu.Lock()
  31. process := tc.process
  32. tc.processMu.Unlock()
  33. if process != nil {
  34. logEntry := &InternalLogEntry{Process: process}
  35. if err := executor.Kill(logEntry); err != nil {
  36. log.WithFields(log.Fields{
  37. "error": err,
  38. }).Warnf("Failed to kill process group on timeout")
  39. }
  40. }
  41. }
  42. }()
  43. return tc, cancel
  44. }
  45. func (tc *timeoutContext) setProcess(process *os.Process) {
  46. tc.processMu.Lock()
  47. tc.process = process
  48. tc.processMu.Unlock()
  49. // If deadline already expired before process was set, kill now
  50. if errors.Is(tc.Err(), context.DeadlineExceeded) && process != nil {
  51. logEntry := &InternalLogEntry{Process: process}
  52. if err := tc.executor.Kill(logEntry); err != nil {
  53. log.WithFields(log.Fields{
  54. "error": err,
  55. }).Warnf("Failed to kill process group on timeout (late registration)")
  56. }
  57. }
  58. }