-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: reap zombie process and opt-out with no-reap flag (#172)
* fix: random waitid error fix #171 * fix(reap): forward signal * refactor: modify reaper to get supercronic exitStatus * fix(reaper): unify signal list & fix signal forward * chore: replace ioutil to io * fix(test): ci timeout * opt-out with no-reap flag Co-authored-by: Josh Raker <[email protected]> * fix: typo on signal * fix: args pass to supercronic * fix(test): remove removed flag * chore: remove misleading comment --------- Co-authored-by: Josh Raker <[email protected]>
- Loading branch information
1 parent
bfb0d97
commit 8b4edf5
Showing
9 changed files
with
176 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* * * * * * * echo 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
* * * * * * * /bin/sleep 1 & exec /bin/sleep 0 | ||
* * * * * * * /bin/sleep 0.1 & exec /bin/sleep 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
|
||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
func forkExec() { | ||
|
||
// run supercronic in other process | ||
pwd, err := os.Getwd() | ||
if err != nil { | ||
logrus.Fatalf("Failed to get current working directory: %s", err.Error()) | ||
return | ||
} | ||
|
||
pattrs := &syscall.ProcAttr{ | ||
Dir: pwd, | ||
Env: os.Environ(), | ||
Files: []uintptr{ | ||
uintptr(syscall.Stdin), | ||
uintptr(syscall.Stdout), | ||
uintptr(syscall.Stderr), | ||
}, | ||
} | ||
args := make([]string, 0, len(os.Args)+1) | ||
// disable reaping for supercronic, avoid no sense warning | ||
args = append(args, os.Args[0], "-no-reap") | ||
args = append(args, os.Args[1:]...) | ||
|
||
pid, err := syscall.ForkExec(args[0], args, pattrs) | ||
if err != nil { | ||
logrus.Fatalf("Failed to fork exec: %s", err.Error()) | ||
return | ||
} | ||
|
||
// forward signal to supercronic | ||
signalToFork(pid) | ||
// got supercronic exit status | ||
wstatus := reapChildren(pid) | ||
os.Exit(wstatus.ExitStatus()) | ||
} | ||
|
||
func signalToFork(pid int) { | ||
p, err := os.FindProcess(pid) | ||
if err != nil { | ||
logrus.Fatalf("Failed findProcess supercronic pid:%d,%s", pid, err.Error()) | ||
} | ||
termChan := make(chan os.Signal, 1) | ||
signal.Notify(termChan, signalList...) | ||
go func() { | ||
for { | ||
s := <-termChan | ||
if err := p.Signal(s); err != nil { | ||
logrus.Errorf("Failed to send signal to supercronic: %s", err.Error()) | ||
} | ||
} | ||
}() | ||
} | ||
|
||
// copy from https://github.com/ramr/go-reaper | ||
// modify for wait exit status of supercronic | ||
// without modify, supercronic exit status may not be obtained | ||
|
||
// Be a good parent - clean up behind the children. | ||
func reapChildren(superCrondPid int) syscall.WaitStatus { | ||
var notifications = make(chan os.Signal, 1) | ||
|
||
go sigChildHandler(notifications) | ||
|
||
// all child | ||
const rpid = -1 | ||
var wstatus syscall.WaitStatus | ||
|
||
for { | ||
var sig = <-notifications | ||
logrus.Debugf("reaper received signal %v\n", sig) | ||
for { | ||
pid, err := syscall.Wait4(rpid, &wstatus, 0, nil) | ||
for syscall.EINTR == err { | ||
pid, err = syscall.Wait4(pid, &wstatus, 0, nil) | ||
} | ||
|
||
if syscall.ECHILD == err { | ||
break | ||
} | ||
|
||
if superCrondPid == pid { | ||
logrus.Debugf("supercronic exit, pid=%d, wstatus=%+v, err=%+v\n", pid, wstatus, err) | ||
return wstatus | ||
} | ||
// note: change output need change test | ||
logrus.Warnf("reaper cleanup: pid=%d, wstatus=%+v\n", | ||
pid, wstatus) | ||
} | ||
} | ||
|
||
} | ||
|
||
// Handle death of child (SIGCHLD) messages. Pushes the signal onto the | ||
// notifications channel if there is a waiter. | ||
func sigChildHandler(notifications chan os.Signal) { | ||
var sigs = make(chan os.Signal, 3) | ||
signal.Notify(sigs, syscall.SIGCHLD) | ||
|
||
for { | ||
var sig = <-sigs | ||
select { | ||
case notifications <- sig: /* published it. */ | ||
default: | ||
/* | ||
* Notifications channel full - drop it to the | ||
* floor. This ensures we don't fill up the SIGCHLD | ||
* queue. The reaper just waits for any child | ||
* process (pid=-1), so we ain't loosing it!! ;^) | ||
*/ | ||
} | ||
} | ||
|
||
} /* End of function sigChildHandler. */ |