commit
This commit is contained in:
		
							
								
								
									
										107
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								main.go
									
									
									
									
									
								
							| @ -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,37 +148,22 @@ 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 { | ||||||
| 		for _, s := range services { | 		switch sig { | ||||||
| 			if s.cmd.Process == nil { | 		case syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT: | ||||||
| 				continue | 			for _, s := range services { | ||||||
| 			} | 				if s.cmd.Process == nil { | ||||||
|  | 					continue | ||||||
| 			syscall.Kill(s.cmd.Process.Pid, (sig).(syscall.Signal)) | 				} | ||||||
| 		} |  | ||||||
| 	} | 				syscall.Kill(s.cmd.Process.Pid, (sig).(syscall.Signal)) | ||||||
| } |  | ||||||
|  |  | ||||||
| func forwardSignals2(services []*Service) { |  | ||||||
| 	sigCh := make(chan os.Signal, 1) |  | ||||||
| 	signal.Notify(sigCh, syscall.SIGCHLD) |  | ||||||
|  |  | ||||||
| 	var once sync.Once |  | ||||||
|  |  | ||||||
| 	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) |  | ||||||
| 				}) |  | ||||||
| 			} | 			} | ||||||
|  | 		case syscall.SIGCHLD: | ||||||
|  | 			debug("chld") | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -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) | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user