🧑💻 Go может принудительно закрывать зависшие subprocess через WaitDelay📝 При автоматизации через os/exec процесс может завершиться, но cmd.Wait() продолжит ждать из-за открытых pipe'ов, оставленных дочерними процессами. WaitDelay позволяет задать максимальное время ожидания после завершения процесса и автоматически закрыть связанные дескрипторы.
📝 Ограничиваем время ожидания завершения командыpackage main
import (
"context"
"fmt"
"os/exec"
"time"
)
func run(ctx context.Context, command string, args ...string) error {
cmd := exec.CommandContext(ctx, command, args...)
cmd.Stdout = nil
cmd.Stderr = nil
// После завершения процесса не ждём бесконечно
// закрытия унаследованных pipe'ов.
cmd.WaitDelay = 5 * time.Second
if err := cmd.Run(); err != nil {
return fmt.Errorf("command failed: %w", err)
}
return nil
}
func main() {
ctx, cancel := context.WithTimeout(
context.Background(),
30*time.Second,
)
defer cancel()
if err := run(ctx, "sh", "-c", "echo deploy started; sleep 2"); err != nil {
fmt.Println(err)
}
}
📌 Как это работает:• CommandContext завершает процесс, если истёк общий таймаут контекста.
• WaitDelay ограничивает дополнительное ожидание после завершения процесса, когда потомки оставили открытые pipe'ы.
• Это особенно полезно для автоматизаторов, которые запускают git, ssh, docker, kubectl, shell-скрипты и другие внешние команды.
❗️ WaitDelay помогает убрать один из неприятных классов зависаний в Go-автоматизации: основной процесс уже завершился, а Wait() всё ещё не возвращается из-за дочерних процессов и открытых дескрипторов. Это особенно ценно для CI/CD-агентов и job-runner'ов, где зависшая задача может занять рабочий слот навсегда.
tags: #go #автоматизация #разработка🧭 @recura_tech 🌐 VK 🌐 MAX