Add graceful service termination

This commit is contained in:
EnumDev 2025-02-23 18:30:03 +02:00
parent a31c319627
commit b04fd51245
2 changed files with 65 additions and 53 deletions

View File

@ -10,6 +10,7 @@ import (
"path" "path"
"strconv" "strconv"
"syscall" "syscall"
"time"
) )
// Build-time variables // Build-time variables
@ -94,6 +95,39 @@ func startServiceManager() {
fmt.Println("Done") fmt.Println("Done")
} }
func stopServiceManager() {
fmt.Println("Stopping service manager... ")
err := syscall.Kill(serviceManagerPid, syscall.SIGTERM)
if err != nil {
log.Println("Could not stop service manager!")
}
// Check if service manager has stopped gracefully, otherwise send sigkill on timeout
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
log.Println("Could not stop service manager!")
err := syscall.Kill(serviceManagerPid, syscall.SIGKILL)
if err != nil {
log.Println("Could not stop service manager!")
}
case <-ticker.C:
p, err := os.FindProcess(serviceManagerPid)
if err != nil {
break
}
err = p.Signal(syscall.Signal(0))
if err != nil {
break
}
}
fmt.Print("Done.")
}
func waitZombieProcesses() { func waitZombieProcesses() {
for { for {
if wpid, _ := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); wpid <= 0 { if wpid, _ := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); wpid <= 0 {
@ -141,17 +175,13 @@ func catchSignals() {
func shutdownSystem() { func shutdownSystem() {
fmt.Println("Shutting down...") fmt.Println("Shutting down...")
fmt.Println("Stopping services... ") stopServiceManager()
err := syscall.Kill(serviceManagerPid, syscall.SIGTERM)
if err != nil { fmt.Println("Syncing disks...")
log.Println("Could not stop service manager!") syscall.Sync()
panic(err)
}
fmt.Print("Done.")
fmt.Println("Sending shutdown syscall...") fmt.Println("Sending shutdown syscall...")
syscall.Sync() err := syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
err = syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -160,17 +190,13 @@ func shutdownSystem() {
func rebootSystem() { func rebootSystem() {
fmt.Println("Rebooting...") fmt.Println("Rebooting...")
fmt.Println("Stopping service manager... ") stopServiceManager()
err := syscall.Kill(serviceManagerPid, syscall.SIGTERM)
if err != nil { fmt.Println("Syncing disks...")
log.Println("Could not stop service manager!") syscall.Sync()
panic(err)
}
fmt.Print("Done.")
fmt.Println("Sending reboot syscall...") fmt.Println("Sending reboot syscall...")
syscall.Sync() err := syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
err = syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -14,6 +14,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
"time"
) )
type EnitServiceState uint8 type EnitServiceState uint8
@ -229,7 +230,7 @@ func (service *EnitService) StartService() error {
return nil return nil
} }
cmd := exec.Command("/bin/sh", "-c", service.StartCmd) cmd := exec.Command("/bin/sh", "-c", "exec "+service.StartCmd)
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return err return err
} }
@ -271,10 +272,28 @@ func (service *EnitService) StopService() error {
return nil return nil
} }
go func() { service.stopChannel <- true }() go func() { service.stopChannel <- true }()
err := service.GetProcess().Signal(syscall.SIGTERM)
if err != nil {
return err
}
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
select {
case <-timer.C:
err := service.GetProcess().Kill() err := service.GetProcess().Kill()
if err != nil { if err != nil {
return err return err
} }
case <-ticker.C:
if service.GetProcess() == nil {
break
}
}
} else { } else {
cmd := exec.Command("/bin/sh", "-c", service.StopCmd) cmd := exec.Command("/bin/sh", "-c", service.StopCmd)
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
@ -307,39 +326,6 @@ func (service *EnitService) RestartService() error {
return nil return nil
} }
func checkForServiceCommand() {
for _, service := range Services {
if _, err := os.Stat(path.Join(service.ServiceRunPath, "start")); err == nil {
err := service.StartService()
if err != nil {
return
}
err = os.Remove(path.Join(service.ServiceRunPath, "start"))
if err != nil {
return
}
} else if _, err := os.Stat(path.Join(service.ServiceRunPath, "stop")); err == nil {
err := service.StopService()
if err != nil {
return
}
err = os.Remove(path.Join(service.ServiceRunPath, "stop"))
if err != nil {
return
}
} else if _, err := os.Stat(path.Join(service.ServiceRunPath, "restart")); err == nil {
err := service.RestartService()
if err != nil {
return
}
err = os.Remove(path.Join(service.ServiceRunPath, "restart"))
if err != nil {
return
}
}
}
}
func listenToSocket() { func listenToSocket() {
conn, err := socket.Accept() conn, err := socket.Accept()
if err != nil { if err != nil {