wip: pipe stdout & stderr
This commit is contained in:
@@ -1,26 +1,69 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitea.suyono.dev/suyono/wingmate"
|
||||
)
|
||||
|
||||
const (
|
||||
serviceTag = "service"
|
||||
)
|
||||
|
||||
func (i *Init) service(wg *sync.WaitGroup, path Path, exitFlag <-chan any) {
|
||||
defer wg.Done()
|
||||
|
||||
var (
|
||||
err error
|
||||
err error
|
||||
iwg *sync.WaitGroup
|
||||
stderr io.ReadCloser
|
||||
stdout io.ReadCloser
|
||||
failStatus bool
|
||||
)
|
||||
|
||||
failStatus = false
|
||||
service:
|
||||
for {
|
||||
cmd := exec.Command(path.Path())
|
||||
if err = cmd.Run(); err != nil {
|
||||
iwg = &sync.WaitGroup{}
|
||||
|
||||
if stdout, err = cmd.StdoutPipe(); err != nil {
|
||||
wingmate.Log().Error().Str(serviceTag, path.Path()).Msgf("stdout pipe: %#v", err)
|
||||
failStatus = true
|
||||
goto fail
|
||||
}
|
||||
iwg.Add(1)
|
||||
go i.pipeReader(iwg, stdout, path.Path())
|
||||
|
||||
if stderr, err = cmd.StderrPipe(); err != nil {
|
||||
wingmate.Log().Error().Str(serviceTag, path.Path()).Msgf("stderr pipe: %#v", err)
|
||||
_ = stdout.Close()
|
||||
failStatus = true
|
||||
goto fail
|
||||
}
|
||||
iwg.Add(1)
|
||||
go i.pipeReader(iwg, stderr, path.Path())
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
wingmate.Log().Error().Msgf("starting service %s error %#v", path.Path(), err)
|
||||
failStatus = true
|
||||
goto fail
|
||||
}
|
||||
|
||||
iwg.Wait()
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
wingmate.Log().Error().Str(serviceTag, path.Path()).Msgf("got error when waiting: %#v", err)
|
||||
}
|
||||
fail:
|
||||
if failStatus {
|
||||
time.Sleep(time.Second)
|
||||
failStatus = false
|
||||
}
|
||||
select {
|
||||
case <-exitFlag:
|
||||
break service
|
||||
@@ -29,3 +72,16 @@ service:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (i *Init) pipeReader(wg *sync.WaitGroup, pipe io.ReadCloser, serviceName string) {
|
||||
defer wg.Done()
|
||||
|
||||
scanner := bufio.NewScanner(pipe)
|
||||
for scanner.Scan() {
|
||||
wingmate.Log().Info().Str(serviceTag, serviceName).Msg(scanner.Text())
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
wingmate.Log().Error().Str(serviceTag, serviceName).Msgf("got error when reading pipe: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ signal:
|
||||
case unix.SIGTERM, unix.SIGINT:
|
||||
if isOpen {
|
||||
close(trigger)
|
||||
wg.Add(1)
|
||||
go i.signalPump(wg, selfExit)
|
||||
isOpen = false
|
||||
}
|
||||
case unix.SIGCHLD:
|
||||
|
||||
55
init/signal-pump.go
Normal file
55
init/signal-pump.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type status int
|
||||
|
||||
const (
|
||||
triggered status = iota
|
||||
expired
|
||||
)
|
||||
|
||||
func (i *Init) signalPump(wg *sync.WaitGroup, selfExit <-chan any) {
|
||||
if seStatus := i.sigTermPump(time.Now(), selfExit); seStatus == triggered {
|
||||
return
|
||||
}
|
||||
|
||||
i.sigKillPump(time.Now(), selfExit)
|
||||
}
|
||||
|
||||
func (i *Init) sigKillPump(startTime time.Time, selfExit <-chan any) {
|
||||
t := time.NewTicker(time.Millisecond * 200)
|
||||
defer t.Stop()
|
||||
|
||||
for time.Since(startTime) < time.Second {
|
||||
_ = unix.Kill(-1, unix.SIGKILL)
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
case <-selfExit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Init) sigTermPump(startTime time.Time, selfExit <-chan any) status {
|
||||
t := time.NewTicker(time.Millisecond * 100)
|
||||
defer t.Stop()
|
||||
|
||||
for time.Since(startTime) < time.Duration(time.Second*4) {
|
||||
_ = unix.Kill(-1, unix.SIGTERM)
|
||||
|
||||
select {
|
||||
case <-t.C:
|
||||
case <-selfExit:
|
||||
return triggered
|
||||
}
|
||||
}
|
||||
|
||||
return expired
|
||||
}
|
||||
Reference in New Issue
Block a user