Skip to content

Commit 63f1c5e

Browse files
committed
Refactor process tracking and signal handling in Python container bootloader
1 parent b15e5f4 commit 63f1c5e

1 file changed

Lines changed: 33 additions & 18 deletions

File tree

sdks/python/container/boot.go

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ var (
6060
provisionEndpoint = flag.String("provision_endpoint", "", "Provision endpoint (required).")
6161
controlEndpoint = flag.String("control_endpoint", "", "Control endpoint (required).")
6262
semiPersistDir = flag.String("semi_persist_dir", "/tmp", "Local semi-persistent directory (optional).")
63+
64+
workerMu sync.Mutex
65+
shuttingDown bool
6366
)
6467

6568
const (
@@ -307,19 +310,12 @@ func launchSDKProcess() error {
307310

308311
workerIds := append([]string{*id}, info.GetSiblingWorkerIds()...)
309312

310-
// Keep track of child PIDs for clean shutdown without zombies
311-
childPids := struct {
312-
v []int
313-
canceled bool
314-
mu sync.Mutex
315-
}{v: make([]int, 0, len(workerIds))}
316-
317313
// Forward trapped signals to child process groups in order to terminate them gracefully and avoid zombies
318314
go func() {
319315
logger.Printf(ctx, "Received signal: %v", <-signalChannel)
320-
childPids.mu.Lock()
321-
childPids.canceled = true
322-
for _, pid := range childPids.v {
316+
workerMu.Lock()
317+
shuttingDown = true
318+
for _, pid := range activePids {
323319
go func(pid int) {
324320
// This goroutine will be canceled if the main process exits before the 5 seconds
325321
// have elapsed, i.e., as soon as all subprocesses have returned from Wait().
@@ -330,7 +326,7 @@ func launchSDKProcess() error {
330326
}(pid)
331327
syscall.Kill(-pid, syscall.SIGTERM)
332328
}
333-
childPids.mu.Unlock()
329+
workerMu.Unlock()
334330
}()
335331

336332
var wg sync.WaitGroup
@@ -342,9 +338,9 @@ func launchSDKProcess() error {
342338
bufLogger := tools.NewBufferedLogger(logger)
343339
errorCount := 0
344340
for {
345-
childPids.mu.Lock()
346-
if childPids.canceled {
347-
childPids.mu.Unlock()
341+
workerMu.Lock()
342+
if shuttingDown {
343+
workerMu.Unlock()
348344
return
349345
}
350346

@@ -369,8 +365,8 @@ func launchSDKProcess() error {
369365

370366
logger.Printf(ctx, "Executing Python (%v): %v %v", envStr, currentProg, strings.Join(currentArgs, " "))
371367
cmd := StartCommandEnv(currentEnv, os.Stdin, bufLogger, bufLogger, currentProg, currentArgs...)
372-
childPids.v = append(childPids.v, cmd.Process.Pid)
373-
childPids.mu.Unlock()
368+
activePids = append(activePids, cmd.Process.Pid)
369+
workerMu.Unlock()
374370

375371
var timer *time.Timer
376372
var profilingTimedOut atomic.Bool
@@ -379,8 +375,8 @@ func launchSDKProcess() error {
379375
if profilingActive && pcfg.StopAfterSec > 0 {
380376
duration := time.Duration(pcfg.StopAfterSec) * time.Second
381377
timer = time.AfterFunc(duration, func() {
382-
childPids.mu.Lock()
383-
defer childPids.mu.Unlock()
378+
workerMu.Lock()
379+
defer workerMu.Unlock()
384380
if cmd.Process != nil {
385381
logger.Printf(ctx, "Profiling timeout of %d seconds reached. Sending SIGINT to worker %s",
386382
pcfg.StopAfterSec, workerId)
@@ -391,6 +387,7 @@ func launchSDKProcess() error {
391387
}
392388

393389
err := cmd.Wait()
390+
unregisterPid(cmd.Process.Pid)
394391
if timer != nil {
395392
timer.Stop()
396393
}
@@ -603,4 +600,22 @@ func logSubmissionEnvDependencies(ctx context.Context, bufLogger *tools.Buffered
603600
return nil
604601
}
605602

603+
var (
604+
activePids []int
605+
)
606606

607+
func unregisterPid(pid int) {
608+
workerMu.Lock()
609+
defer workerMu.Unlock()
610+
activePids = slices.DeleteFunc(activePids, func(p int) bool {
611+
return p == pid
612+
})
613+
}
614+
615+
func getActivePids() []int {
616+
workerMu.Lock()
617+
defer workerMu.Unlock()
618+
pids := make([]int, len(activePids))
619+
copy(pids, activePids)
620+
return pids
621+
}

0 commit comments

Comments
 (0)