프로세스 종료시 알림
This commit is contained in:
@ -17,6 +17,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
@ -67,15 +68,30 @@ type HoustonClient interface {
|
||||
Start()
|
||||
}
|
||||
|
||||
var seq = int32(1)
|
||||
|
||||
type procmeta struct {
|
||||
id int32
|
||||
cmd *exec.Cmd
|
||||
name string
|
||||
args []string
|
||||
version string
|
||||
state protos.ProcessState
|
||||
state int32
|
||||
stdin io.WriteCloser
|
||||
}
|
||||
|
||||
func (pm *procmeta) isState(s protos.ProcessState) bool {
|
||||
return atomic.LoadInt32(&pm.state) == int32(s)
|
||||
}
|
||||
|
||||
func (pm *procmeta) getState() protos.ProcessState {
|
||||
return protos.ProcessState(atomic.LoadInt32(&pm.state))
|
||||
}
|
||||
|
||||
func (pm *procmeta) setState(s protos.ProcessState) {
|
||||
atomic.StoreInt32(&pm.state, int32(s))
|
||||
}
|
||||
|
||||
type houstonClient struct {
|
||||
childProcs []*procmeta
|
||||
extraMetrics unsafe.Pointer // map[string]float32
|
||||
@ -167,7 +183,7 @@ func (hc *houstonClient) makeOperationQueryRequest() *protos.OperationQueryReque
|
||||
Name: child.name,
|
||||
Args: child.args,
|
||||
Version: child.version,
|
||||
State: child.state,
|
||||
State: child.getState(),
|
||||
Pid: int32(child.cmd.Process.Pid),
|
||||
})
|
||||
}
|
||||
@ -283,7 +299,7 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
||||
var newprocs []*procmeta
|
||||
for _, proc := range hc.childProcs {
|
||||
if proc.cmd == exited {
|
||||
if proc.state == protos.ProcessState_Running || proc.state == protos.ProcessState_Restart {
|
||||
if proc.isState(protos.ProcessState_Running) || proc.isState(protos.ProcessState_Restart) {
|
||||
go func(proc *procmeta) {
|
||||
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||
proc.cmd.Process.Signal(os.Kill)
|
||||
@ -291,7 +307,7 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
||||
proc.cmd.Wait()
|
||||
proc.cmd.Process.Release()
|
||||
|
||||
if proc.state == protos.ProcessState_Restart {
|
||||
if proc.isState(protos.ProcessState_Restart) {
|
||||
hc.startChildProcess(&shared.StartProcessRequest{
|
||||
Version: proc.version,
|
||||
Name: proc.name,
|
||||
@ -407,6 +423,30 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
||||
if err := hc.uploadFiles(&ur); err != nil {
|
||||
logger.Println(err)
|
||||
}
|
||||
|
||||
case shared.Exception:
|
||||
idstr := resp.Args["id"]
|
||||
id64, _ := strconv.ParseInt(idstr, 10, 0)
|
||||
id := int32(id64)
|
||||
|
||||
var killing *procmeta
|
||||
var remains []*procmeta
|
||||
for _, meta := range hc.childProcs {
|
||||
if meta.id == id {
|
||||
killing = meta
|
||||
} else {
|
||||
remains = append(remains, meta)
|
||||
}
|
||||
}
|
||||
|
||||
if killing != nil {
|
||||
killing.cmd.Wait()
|
||||
killing.cmd.Process.Release()
|
||||
}
|
||||
|
||||
hc.childProcs = remains
|
||||
|
||||
op.Refresh(context.Background(), hc.makeOperationQueryRequest())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -428,7 +468,7 @@ func (hc *houstonClient) Start() {
|
||||
for _, proc := range hc.childProcs {
|
||||
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||
proc.cmd.Process.Signal(os.Kill)
|
||||
proc.state = protos.ProcessState_Stopping
|
||||
proc.setState(protos.ProcessState_Stopping)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -153,23 +153,27 @@ func prepareProcessLaunch(storageRoot string, req *shared.StartProcessRequest) *
|
||||
|
||||
if err == nil && fi.IsDir() {
|
||||
exefile := "./" + path.Clean(strings.TrimPrefix(req.Args[0], "/"))
|
||||
err = set_permission(path.Join(verpath, exefile))
|
||||
if err != nil {
|
||||
logger.Println("set_permission failed :", err)
|
||||
return nil
|
||||
}
|
||||
os.Chmod(path.Join(verpath, exefile), 0777)
|
||||
|
||||
exef, _ := os.Executable()
|
||||
cmd := exec.Command(path.Join(path.Dir(exef), verpath, exefile), req.Args[1:]...)
|
||||
|
||||
if err := run_prelaunch_script(cmd.Args[0]); err != nil {
|
||||
logger.Println("run_prelaunch_script failed :", cmd.Args[0], err)
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd.Dir = verpath
|
||||
stdin, _ := cmd.StdinPipe()
|
||||
|
||||
seq++
|
||||
return &procmeta{
|
||||
id: seq,
|
||||
cmd: cmd,
|
||||
name: req.Name,
|
||||
args: req.Args,
|
||||
version: req.Version,
|
||||
state: protos.ProcessState_Stopped,
|
||||
state: int32(protos.ProcessState_Stopped),
|
||||
stdin: stdin,
|
||||
}
|
||||
}
|
||||
@ -236,6 +240,17 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
||||
var metricBuffer []byte
|
||||
metricValues := make(map[string]metricValueAccessor)
|
||||
|
||||
defer func() {
|
||||
if meta.isState(protos.ProcessState_Running) {
|
||||
hc.operationChan <- &protos.OperationQueryResponse{
|
||||
Operation: string(shared.Exception),
|
||||
Args: map[string]string{
|
||||
"id": fmt.Sprintf("%d", meta.id),
|
||||
},
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
buff, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
@ -319,11 +334,11 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
||||
go stdReader(meta.name, stdout)
|
||||
|
||||
logger.Println("startChildProcess :", meta.cmd.Args)
|
||||
|
||||
err = meta.cmd.Start()
|
||||
if err == nil {
|
||||
meta.state = protos.ProcessState_Running
|
||||
meta.setState(protos.ProcessState_Running)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@ -389,7 +404,7 @@ func (hc *houstonClient) stopChildProcess(req *shared.StopProcessRequest, op pro
|
||||
var remains []*procmeta
|
||||
var killing []*procmeta
|
||||
for _, proc := range hc.childProcs {
|
||||
if proc.state != protos.ProcessState_Running {
|
||||
if !proc.isState(protos.ProcessState_Running) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -419,7 +434,7 @@ func (hc *houstonClient) stopChildProcess(req *shared.StopProcessRequest, op pro
|
||||
|
||||
if len(killing) > 0 {
|
||||
for _, proc := range killing {
|
||||
proc.state = protos.ProcessState_Stopping
|
||||
proc.setState(protos.ProcessState_Stopping)
|
||||
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||
proc.cmd.Process.Signal(os.Kill)
|
||||
}
|
||||
@ -453,7 +468,7 @@ func (hc *houstonClient) restartChildProcess(req *shared.RestartProcessRequest,
|
||||
}
|
||||
}
|
||||
|
||||
proc.state = protos.ProcessState_Restart
|
||||
proc.setState(protos.ProcessState_Restart)
|
||||
op.Refresh(context.Background(), hc.makeOperationQueryRequest())
|
||||
hc.exitChan <- proc.cmd
|
||||
|
||||
|
||||
47
client/platform_linux.go
Normal file
47
client/platform_linux.go
Normal file
@ -0,0 +1,47 @@
|
||||
//go:build client && linux
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
)
|
||||
|
||||
func run_prelaunch_script(exepath string) error {
|
||||
scriptPath := path.Join(path.Dir(exepath), "prelaunch.sh")
|
||||
fi, err := os.Stat(scriptPath)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
logger.Println("prelaunch.sh not exists :", scriptPath, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi == nil {
|
||||
logger.Println("prelaunch.sh fi is nil :", scriptPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Chmod(scriptPath, 0777)
|
||||
|
||||
logger.Println("run_prelaunch_script :", "/bin/bash", scriptPath, exepath)
|
||||
return exec.Command("/bin/bash", scriptPath, exepath).Run()
|
||||
}
|
||||
|
||||
func run_postlaunch_script(exepath string) error {
|
||||
scriptPath := path.Join(path.Dir(exepath), "postlaunch.sh")
|
||||
fi, err := os.Stat(scriptPath)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Chmod(scriptPath, 0777)
|
||||
return exec.Command("/bin/bash", scriptPath, exepath).Run()
|
||||
}
|
||||
42
client/platform_windows.go
Normal file
42
client/platform_windows.go
Normal file
@ -0,0 +1,42 @@
|
||||
//go:build !(client && linux)
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
)
|
||||
|
||||
func run_prelaunch_script(exepath string) error {
|
||||
scriptPath := path.Join(path.Dir(exepath), "prelaunch.bat")
|
||||
fi, err := os.Stat(scriptPath)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Chmod(scriptPath, 0777)
|
||||
|
||||
return exec.Command("cmd", scriptPath).Run()
|
||||
}
|
||||
|
||||
func run_postlaunch_script(exepath string) error {
|
||||
scriptPath := path.Join(path.Dir(exepath), "postlaunch.bat")
|
||||
fi, err := os.Stat(scriptPath)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Chmod(scriptPath, 0777)
|
||||
return exec.Command("cmd", scriptPath).Run()
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
//go:build !(client && linux)
|
||||
|
||||
package client
|
||||
|
||||
func set_permission(path string) error {
|
||||
return nil
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
//go:build client && linux
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func init() {
|
||||
file, _ := os.OpenFile("setcap.sh", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0777)
|
||||
file.Write([]byte("sudo setcap 'cap_net_bind_service=+ep' $1"))
|
||||
file.Sync()
|
||||
file.Close()
|
||||
}
|
||||
|
||||
func set_permission(path string) error {
|
||||
os.Chmod(path, 0777)
|
||||
cmd := exec.Command("/bin/bash", "./setcap.sh", path)
|
||||
return cmd.Run()
|
||||
}
|
||||
2
go.mod
2
go.mod
@ -10,7 +10,7 @@ require (
|
||||
golang.org/x/text v0.10.0
|
||||
google.golang.org/grpc v1.56.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20231123013925-8adef2adb814
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20231123110857-d672b5dd90ec
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
4
go.sum
4
go.sum
@ -120,5 +120,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20231123013925-8adef2adb814 h1:3K7YBlNbm7AJJLt8LJ2iDHxgJG5vL7hE1VvdG7VwKCM=
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20231123013925-8adef2adb814/go.mod h1:XvklTTSvQX5uviivGBcZo8eIL+mV94W2e4uBBXcT5JY=
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20231123110857-d672b5dd90ec h1:hB0bjNdS/5xClLR/vhPcACLRbpuxaLiCRwH6PV4a6EU=
|
||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20231123110857-d672b5dd90ec/go.mod h1:XvklTTSvQX5uviivGBcZo8eIL+mV94W2e4uBBXcT5JY=
|
||||
|
||||
@ -10,13 +10,14 @@ import (
|
||||
type Operation string
|
||||
|
||||
const (
|
||||
Deploy = Operation("deploy")
|
||||
Withdraw = Operation("withdraw")
|
||||
Upgrade = Operation("upgrade")
|
||||
Start = Operation("start")
|
||||
Restart = Operation("restart")
|
||||
Stop = Operation("stop")
|
||||
Upload = Operation("upload")
|
||||
Deploy = Operation("deploy")
|
||||
Withdraw = Operation("withdraw")
|
||||
Upgrade = Operation("upgrade")
|
||||
Start = Operation("start")
|
||||
Restart = Operation("restart")
|
||||
Stop = Operation("stop")
|
||||
Upload = Operation("upload")
|
||||
Exception = Operation("exception")
|
||||
)
|
||||
|
||||
type DeployRequest struct {
|
||||
|
||||
Reference in New Issue
Block a user