|
@ -5,22 +5,24 @@ import ( |
|
|
"os" |
|
|
"os" |
|
|
"os/exec" |
|
|
"os/exec" |
|
|
"syscall" |
|
|
"syscall" |
|
|
|
|
|
"time" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var subProcess []*Process |
|
|
|
|
|
|
|
|
type Process struct { |
|
|
type Process struct { |
|
|
done bool |
|
|
|
|
|
enable bool |
|
|
enable bool |
|
|
caption string |
|
|
name string |
|
|
command []string |
|
|
command []string |
|
|
process *exec.Cmd |
|
|
process *exec.Cmd |
|
|
|
|
|
exit bool |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func newProcess(command ...string) *Process { |
|
|
func newProcess(command ...string) *Process { |
|
|
process := new(Process) |
|
|
process := new(Process) |
|
|
process.enable = true |
|
|
process.name = command[0] |
|
|
process.command = command |
|
|
process.command = command |
|
|
process.caption = command[0] |
|
|
log.Debugf("New process %s -> %v", process.name, process.command) |
|
|
log.Debugf("New process %s -> %v", process.caption, process.command) |
|
|
|
|
|
return process |
|
|
return process |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -32,57 +34,78 @@ func (p *Process) startProcess(isStdout bool, isStderr bool) { |
|
|
if isStderr { |
|
|
if isStderr { |
|
|
p.process.Stderr = os.Stderr |
|
|
p.process.Stderr = os.Stderr |
|
|
} |
|
|
} |
|
|
|
|
|
p.enable = true |
|
|
err := p.process.Start() |
|
|
err := p.process.Start() |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Errorf("Failed to start %s -> %v", p.caption, err) |
|
|
log.Errorf("Failed to start %s -> %v", p.name, err) |
|
|
} |
|
|
} |
|
|
log.Infof("Start process %s -> PID = %d", p.caption, p.process.Process.Pid) |
|
|
log.Infof("Start process %s -> PID = %d", p.name, p.process.Process.Pid) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (p *Process) isProcessAlive() bool { |
|
|
|
|
|
return p.process.ProcessState == nil |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (p *Process) sendSignal(signal syscall.Signal) { |
|
|
func (p *Process) sendSignal(signal syscall.Signal) { |
|
|
if p != nil { |
|
|
//defer func() {
|
|
|
err := p.process.Process.Signal(signal) |
|
|
// _ = recover()
|
|
|
if err != nil { |
|
|
//}()
|
|
|
log.Errorf("Send signal %v to process %s error -> %v", signal, p.caption, err) |
|
|
if p.process != nil && p.process.ProcessState == nil { |
|
|
} |
|
|
log.Debugf("Send signal %v to %s", signal, p.name) |
|
|
|
|
|
_ = p.process.Process.Signal(signal) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (p *Process) waitProcess() { |
|
|
func (p *Process) waitProcess() { |
|
|
|
|
|
if p.process != nil { |
|
|
err := p.process.Wait() |
|
|
err := p.process.Wait() |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
log.Warningf("Wait process %s -> %v", p.caption, err) |
|
|
log.Warningf("Wait process %s -> %v", p.name, err) |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (p *Process) disableProcess() { |
|
|
|
|
|
if p != nil { |
|
|
|
|
|
p.enable = false |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func daemonSub(sub *Process) { |
|
|
func daemonSub(sub *Process) { |
|
|
for sub.isProcessAlive() { |
|
|
for sub.process.ProcessState == nil { |
|
|
sub.waitProcess() |
|
|
sub.waitProcess() |
|
|
} |
|
|
} |
|
|
log.Warningf("Catch process %s exit", sub.caption) |
|
|
log.Warningf("Catch process %s exit", sub.name) |
|
|
if sub.enable { |
|
|
if !sub.enable { |
|
|
|
|
|
log.Debugf("Process %s disabled -> stop daemon", sub.name) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
sub.startProcess(true, true) |
|
|
sub.startProcess(true, true) |
|
|
log.Infof("Process %s restart success", xray.caption) |
|
|
log.Infof("Process %s restart success", sub.name) |
|
|
daemonSub(sub) |
|
|
daemonSub(sub) |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func daemon(sub *Process) { |
|
|
func daemon(sub *Process) { |
|
|
if sub != nil && sub.enable { |
|
|
if !sub.enable { |
|
|
log.Infof("Start daemon of process %s", sub.caption) |
|
|
log.Infof("Process %s disabled -> skip daemon", sub.name) |
|
|
|
|
|
sub.exit = true |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
log.Infof("Start daemon of process %s", sub.name) |
|
|
go func() { |
|
|
go func() { |
|
|
daemonSub(sub) |
|
|
daemonSub(sub) |
|
|
sub.done = true |
|
|
log.Infof("Process %s daemon exit", sub.name) |
|
|
|
|
|
sub.exit = true |
|
|
}() |
|
|
}() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func exit() { |
|
|
|
|
|
log.Warningf("Start exit process") |
|
|
|
|
|
for _, sub := range subProcess { |
|
|
|
|
|
sub.enable = false |
|
|
|
|
|
if sub.process != nil { |
|
|
|
|
|
sub.sendSignal(syscall.SIGTERM) |
|
|
|
|
|
log.Infof("Send kill signal to process %s", sub.name) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
var allExit bool |
|
|
|
|
|
log.Info("Wait all sub process exit") |
|
|
|
|
|
for !allExit { |
|
|
|
|
|
time.Sleep(10 * time.Millisecond) // delay 10ms
|
|
|
|
|
|
allExit = true |
|
|
|
|
|
for _, sub := range subProcess { |
|
|
|
|
|
allExit = allExit && sub.exit //(sub.process.ProcessState != nil)
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
log.Infof("Exit complete") |
|
|
} |
|
|
} |
|
|