91 lines
1.4 KiB
Go
91 lines
1.4 KiB
Go
|
package initservices
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"time"
|
||
|
|
||
|
"github.com/spf13/cobra"
|
||
|
plog "novit.nc/direktil/pkg/log"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
delays = []time.Duration{
|
||
|
1 * time.Second,
|
||
|
2 * time.Second,
|
||
|
4 * time.Second,
|
||
|
8 * time.Second,
|
||
|
}
|
||
|
|
||
|
crashForgiveDelay = 10 * time.Minute
|
||
|
)
|
||
|
|
||
|
func Command() (c *cobra.Command) {
|
||
|
c = &cobra.Command{
|
||
|
Use: "services",
|
||
|
Short: "run user services",
|
||
|
Run: run,
|
||
|
}
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func run(c *cobra.Command, args []string) {
|
||
|
paths, err := filepath.Glob("/etc/direktil/services/*")
|
||
|
|
||
|
if err != nil && !os.IsNotExist(err) {
|
||
|
log.Fatal("failed to list services: ", err)
|
||
|
}
|
||
|
|
||
|
for _, path := range paths {
|
||
|
stat, err := os.Stat(path)
|
||
|
if err != nil {
|
||
|
log.Fatalf("failed to stat %s: %v", path, err)
|
||
|
}
|
||
|
|
||
|
if stat.Mode()&0100 == 0 {
|
||
|
// not executable
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
go runService(path)
|
||
|
}
|
||
|
|
||
|
select {}
|
||
|
}
|
||
|
|
||
|
func runService(svcPath string) {
|
||
|
svc := filepath.Base(svcPath)
|
||
|
|
||
|
logger := plog.Get(svc)
|
||
|
plog.EnableFiles()
|
||
|
|
||
|
n := 0
|
||
|
for {
|
||
|
lastStart := time.Now()
|
||
|
|
||
|
cmd := exec.Command(svcPath)
|
||
|
cmd.Stdout = logger
|
||
|
cmd.Stderr = logger
|
||
|
err := cmd.Run()
|
||
|
|
||
|
if time.Since(lastStart) > crashForgiveDelay {
|
||
|
n = 0
|
||
|
}
|
||
|
|
||
|
if err == nil {
|
||
|
logger.Taintf(plog.Error, "service exited (%v), waiting %v", err, delays[n])
|
||
|
} else {
|
||
|
logger.Taintf(plog.Error, "service exited on error (%v), waiting %v", err, delays[n])
|
||
|
}
|
||
|
|
||
|
time.Sleep(delays[n])
|
||
|
|
||
|
if n+1 < len(delays) {
|
||
|
n++
|
||
|
}
|
||
|
}
|
||
|
}
|