Skip to content
This repository was archived by the owner on Jul 28, 2023. It is now read-only.

Commit d5a912a

Browse files
kewegnerchilanti
authored andcommitted
Signal handler improved (#51)
* temporary key change * reverted key * change image name and remove script file * image name changes CMD added * new branch * PR comments and logging
1 parent 5e429f1 commit d5a912a

1 file changed

Lines changed: 89 additions & 7 deletions

File tree

main.go

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020
"os"
2121
"os/exec"
22+
"os/signal"
2223
"regexp"
2324
"strconv"
2425
"strings"
@@ -308,7 +309,7 @@ func setupEnvironmentVars() error {
308309
return err
309310
}
310311

311-
func killProcess(theProcessType ProcessType) error {
312+
func killProcess(theProcessType ProcessType, checkAttempts int) error {
312313
var processPid int
313314
var err error
314315
if theProcessType == server {
@@ -319,10 +320,24 @@ func killProcess(theProcessType ProcessType) error {
319320
ControllerDebug.log("Attempting to kill pid: ", processPid)
320321

321322
if processPid != 0 {
323+
// Check to see if the process is still alive to avoid unncessary kill steps
324+
if cmps.processes[theProcessType].Signal(syscall.Signal(0)) != nil {
325+
ControllerDebug.log("No such process for pid: ", processPid)
326+
err = nil
327+
} else {
322328

323-
ControllerDebug.log("Killing pid: ", processPid)
324-
err = syscall.Kill(-processPid, syscall.SIGINT)
325-
329+
ControllerDebug.log("Killing pid: ", processPid)
330+
err = syscall.Kill(-processPid, syscall.SIGINT)
331+
// If checkAttempts speified check and wait to make sure process was killed.
332+
for i := 0; i < checkAttempts; i++ {
333+
ControllerDebug.log("Process check ", theProcessType, i)
334+
if cmps.processes[theProcessType].Signal(syscall.Signal(0)) != nil {
335+
break //process is dead
336+
} else {
337+
time.Sleep(2 * time.Second)
338+
}
339+
}
340+
}
326341
cmps.processes[theProcessType] = nil
327342
cmps.pids[theProcessType] = 0
328343
if err != nil {
@@ -445,7 +460,6 @@ func runWatcher(fileChangeCommand string, dirs []string, killServer bool) error
445460

446461
case err := <-w.Error:
447462
ControllerWarning.log("An error occured in the file watcher ", err)
448-
449463
case <-w.Closed:
450464
ControllerDebug.log("The file watcher is now closed")
451465
return
@@ -526,19 +540,20 @@ func runCommands(commandString string, theProcessType ProcessType, killServer bo
526540
// This is a watcher
527541
if killServer {
528542
ControllerDebug.log("APPSODY_RUN/DEBUG/TEST_ON_KILL is true, attempting to kill the corresponding process.")
529-
err = killProcess(server)
543+
err = killProcess(server, 0)
530544
if err != nil {
531545
// do nothing we continue after kill errors
532546
ControllerWarning.log("The attempt to kill the process received an error ", err)
533547
}
534548
}
535549
ControllerDebug.log("Killing the APPSODY_RUN/DEBUG/TEST_ON_CHANGE process.")
536550

537-
err = killProcess(fileWatcher)
551+
err = killProcess(fileWatcher, 0)
538552
if err != nil {
539553
// do nothing we continue after kill errors
540554
ControllerWarning.log("Killing the the APPSODY_RUN/DEBUG/TEST_ON_CHANGE process received error ", err)
541555
}
556+
go reapChildProcesses(2)
542557

543558
commandToUse := commandString
544559
processTypeToUse := fileWatcher
@@ -695,6 +710,33 @@ func main() {
695710

696711
go runCommands(startCommand, server, false, false)
697712
}
713+
714+
c := make(chan os.Signal, 1)
715+
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
716+
go func() {
717+
<-c
718+
cmps.mu.Lock()
719+
defer cmps.mu.Unlock()
720+
ControllerDebug.log("Inside signal handler for controller")
721+
ControllerDebug.log("Killing the ON_CHANGE process")
722+
// In practice either the fileWatcher or server process will be alive, not both
723+
err := killProcess(fileWatcher, 2) // we give 2 *2 seconds to kill the filewatcher/ON_CHANGE process
724+
if err != nil {
725+
ControllerError.log("Received error during signal handler killing ON_CHANGE process", err)
726+
}
727+
ControllerDebug.log("Killing the server process")
728+
err = killProcess(server, 2) // we give 2 *2 seconds to kill the server process
729+
if err != nil {
730+
ControllerError.log("Received error during signal handler killing the RUN/TEST/DEBUG process", err)
731+
}
732+
// 5 * 1 second waiting for reaping of child processes
733+
// This call is allowed to complete by the fact that the docker stop allows 10 seconds for processeing
734+
// prior to the sig kill
735+
go reapChildProcesses(5) //run separately to make sure that we don't block
736+
737+
ControllerDebug.log("Done processing controller signal handler.")
738+
}()
739+
698740
if fileChangeCommand != "" && !disableWatcher {
699741

700742
err = runWatcher(fileChangeCommand, dirs, stopWatchServerOnChange)
@@ -709,3 +751,43 @@ func main() {
709751
}
710752

711753
}
754+
755+
func reapChildProcesses(maxLimit int) {
756+
countLimit := 0
757+
758+
for {
759+
760+
var wstatus syscall.WaitStatus
761+
//WNOHANG means return if there are no child processes to wait for
762+
//This command will wait for processes that hae been reassigned
763+
// to pid 1 after the server or fileWatcher/ON_CHANGE process is terminated
764+
pid, err := syscall.Wait4(-1, &wstatus, syscall.WNOHANG, nil)
765+
ControllerDebug.log("Reaper pid/err is: ", pid, err)
766+
// If it is 0 that means no process was waiting atm, we will sleep and give a little more time
767+
if pid == 0 && countLimit < maxLimit && err == nil {
768+
ControllerDebug.log("Reaper sleeping 1 second: ", pid)
769+
time.Sleep(1 * time.Second)
770+
countLimit++
771+
}
772+
773+
if syscall.EINTR == err {
774+
// A Signal Interupt occured and we should stop processing
775+
ControllerDebug.log("Signal Interrupt: ", err)
776+
break
777+
}
778+
//This value means no child processes left waiting.
779+
if syscall.ECHILD == err {
780+
ControllerDebug.log("No more child processes: ", err)
781+
break
782+
}
783+
784+
ControllerDebug.log("Max limit count: ", countLimit)
785+
786+
if countLimit >= maxLimit {
787+
ControllerDebug.log("Max limit reached: ", maxLimit)
788+
break
789+
}
790+
791+
}
792+
793+
}

0 commit comments

Comments
 (0)