This commit is contained in:
Timofey.Kovalev
2025-07-23 13:57:55 +03:00
parent 1fe3db41c2
commit d038dafd4f

100
main.go
View File

@ -2,6 +2,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
@ -15,6 +16,12 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
var ch chan struct{}
func init() {
ch = make(chan struct{})
}
type Service struct { type Service struct {
CMD string `json:"cmd"` CMD string `json:"cmd"`
Args []string `json:"args"` Args []string `json:"args"`
@ -31,9 +38,9 @@ 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) { // func printInfo(info string) {
fmt.Fprintf(os.Stderr, "[qini] Inf: %s\n", info) // fmt.Fprintf(os.Stderr, "[qini] Inf: %s\n", info)
} // }
var verbose bool var verbose bool
@ -60,27 +67,31 @@ 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) int { func runServices(services []*Service) error {
if len(services) == 0 { if len(services) == 0 {
printInfo("no services in config") return errors.New("no services in config")
return 1
} }
var ( var (
r *io.PipeReader r *io.PipeReader
w *io.PipeWriter w *io.PipeWriter
lock sync.Mutex
once sync.Once
wg sync.WaitGroup
exitCode int
) )
lock.Lock()
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...)
@ -103,42 +114,20 @@ func runServices(services []*Service) int {
s.cmd.Stdout = os.Stdout s.cmd.Stdout = os.Stdout
} }
wg.Add(1)
go func(w *io.PipeWriter) {
defer wg.Done()
defer func() {
if w != nil {
w.Close()
}
once.Do(func() {
lock.Lock()
defer lock.Unlock()
debug("stop all services")
stopAllServices(services)
exitCode = s.cmd.ProcessState.ExitCode()
})
}()
debug("run service [%s]", s.CMD) debug("run service [%s]", s.CMD)
err := s.cmd.Run() err := s.cmd.Start()
if err != nil { if err != nil {
printErr(err) printErr(err)
} }
debug("service [%s] done, err: [%v]", s.CMD, err)
}(w) go func(s *Service, w *io.PipeWriter) {
s.cmd.Wait()
w.Close()
debug("service done [%s]", s.CMD)
}(s, w)
} }
lock.Unlock() return nil
debug("wait servises")
wg.Wait()
debug("all servises stoped")
return exitCode
} }
func loadConfig(cfg *Config, configFile string) error { func loadConfig(cfg *Config, configFile string) error {
@ -172,18 +161,24 @@ func forwardSignals2(services []*Service) {
sigCh := make(chan os.Signal, 1) sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGCHLD) signal.Notify(sigCh, syscall.SIGCHLD)
for _ = range sigCh { var once sync.Once
printInfo("chld")
for _, c := range services {
if c.cmd.ProcessState != nil {
for range sigCh {
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)
})
} }
} }
} }
} }
func main() { func main() {
verbose = true verbose = false
err := unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) err := unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)
if err != nil { if err != nil {
@ -192,6 +187,7 @@ func main() {
var configFile string var configFile string
flag.StringVar(&configFile, "c", "./config.json", "JSON config file") flag.StringVar(&configFile, "c", "./config.json", "JSON config file")
flag.BoolVar(&verbose, "v", false, "Show debug output")
flag.Parse() flag.Parse()
var cfg Config var cfg Config
@ -205,6 +201,8 @@ func main() {
go forwardSignals(cfg.Services) go forwardSignals(cfg.Services)
go forwardSignals2(cfg.Services) go forwardSignals2(cfg.Services)
exitCode := runServices(cfg.Services) runServices(cfg.Services)
os.Exit(exitCode) //os.Exit(exitCode)
<-ch
} }