This commit is contained in:
Timofey.Kovalev
2025-07-25 14:40:17 +03:00
parent d038dafd4f
commit a5055b226f

93
main.go
View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
"io"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@ -35,13 +34,9 @@ type Config struct {
} }
func printErr(err error) { func printErr(err error) {
fmt.Fprintf(os.Stderr, "[qini] Err: %s\n", err.Error()) fmt.Fprintf(os.Stderr, "[qini] err: %s\n", err.Error())
} }
// func printInfo(info string) {
// fmt.Fprintf(os.Stderr, "[qini] Inf: %s\n", info)
// }
var verbose bool var verbose bool
func debug(s string, a ...any) { func debug(s string, a ...any) {
@ -67,36 +62,29 @@ func stopAllServices(services []*Service) {
} }
}(s) }(s)
} }
loop:
for {
time.Sleep(time.Second)
for _, s := range services {
if s.cmd.Process != nil && s.cmd.ProcessState == nil {
continue loop
}
}
os.Exit(1)
}
} }
func runServices(services []*Service) error { func runServices(services []*Service) (int, error) {
if len(services) == 0 { if len(services) == 0 {
return errors.New("no services in config") return 0, errors.New("no services in config")
} }
var ( var (
r *io.PipeReader r *os.File
w *io.PipeWriter w *os.File
once sync.Once
exitCode int
wg sync.WaitGroup
err error
) )
for i, s := range services { for i, s := range services {
s.cmd = exec.Command(s.CMD, s.Args...) s.cmd = exec.Command(s.CMD, s.Args...)
s.cmd.SysProcAttr = &syscall.SysProcAttr{ s.cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: false, Setsid: true,
} }
if s.PWD != "" { if s.PWD != "" {
@ -105,10 +93,16 @@ func runServices(services []*Service) error {
if r != nil { if r != nil {
s.cmd.Stdin = r s.cmd.Stdin = r
} else {
s.cmd.Stdin = os.Stdin
} }
if i+1 < len(services) { if i+1 < len(services) {
r, w = io.Pipe() r, w, err = os.Pipe()
if err != nil {
return 0, err
}
s.cmd.Stdout = w s.cmd.Stdout = w
} else { } else {
s.cmd.Stdout = os.Stdout s.cmd.Stdout = os.Stdout
@ -120,14 +114,26 @@ func runServices(services []*Service) error {
printErr(err) printErr(err)
} }
go func(s *Service, w *io.PipeWriter) { wg.Add(1)
go func(s *Service, w *os.File) {
defer wg.Done()
s.cmd.Wait() s.cmd.Wait()
w.Close() w.Close()
debug("service done [%s]", s.CMD) debug("service done [%s]", s.CMD)
exitCode = s.cmd.ProcessState.ExitCode()
once.Do(func() {
debug("stop all services")
stopAllServices(services)
})
}(s, w) }(s, w)
} }
return nil wg.Wait()
return exitCode, nil
} }
func loadConfig(cfg *Config, configFile string) error { func loadConfig(cfg *Config, configFile string) error {
@ -142,11 +148,13 @@ func loadConfig(cfg *Config, configFile string) error {
} }
func forwardSignals(services []*Service) { func forwardSignals(services []*Service) {
signals := []os.Signal{syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT} signals := []os.Signal{syscall.SIGCHLD, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT}
sigCh := make(chan os.Signal, 1) sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, signals...) signal.Notify(sigCh, signals...)
for sig := range sigCh { for sig := range sigCh {
switch sig {
case syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT:
for _, s := range services { for _, s := range services {
if s.cmd.Process == nil { if s.cmd.Process == nil {
continue continue
@ -154,25 +162,8 @@ func forwardSignals(services []*Service) {
syscall.Kill(s.cmd.Process.Pid, (sig).(syscall.Signal)) syscall.Kill(s.cmd.Process.Pid, (sig).(syscall.Signal))
} }
} case syscall.SIGCHLD:
}
func forwardSignals2(services []*Service) {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGCHLD)
var once sync.Once
for range sigCh {
debug("chld") debug("chld")
for _, c := range services {
debug("%v", c.cmd.ProcessState)
if c.cmd.ProcessState != nil {
once.Do(func() {
debug("stop all services")
stopAllServices(services)
})
}
} }
} }
} }
@ -199,10 +190,12 @@ func main() {
} }
go forwardSignals(cfg.Services) go forwardSignals(cfg.Services)
go forwardSignals2(cfg.Services)
runServices(cfg.Services) exitCode, err := runServices(cfg.Services)
//os.Exit(exitCode) if err != nil {
printErr(err)
os.Exit(123)
}
<-ch os.Exit(exitCode)
} }