프로세스 종료시 알림
This commit is contained in:
@ -17,6 +17,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -67,15 +68,30 @@ type HoustonClient interface {
|
|||||||
Start()
|
Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var seq = int32(1)
|
||||||
|
|
||||||
type procmeta struct {
|
type procmeta struct {
|
||||||
|
id int32
|
||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
version string
|
version string
|
||||||
state protos.ProcessState
|
state int32
|
||||||
stdin io.WriteCloser
|
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 {
|
type houstonClient struct {
|
||||||
childProcs []*procmeta
|
childProcs []*procmeta
|
||||||
extraMetrics unsafe.Pointer // map[string]float32
|
extraMetrics unsafe.Pointer // map[string]float32
|
||||||
@ -167,7 +183,7 @@ func (hc *houstonClient) makeOperationQueryRequest() *protos.OperationQueryReque
|
|||||||
Name: child.name,
|
Name: child.name,
|
||||||
Args: child.args,
|
Args: child.args,
|
||||||
Version: child.version,
|
Version: child.version,
|
||||||
State: child.state,
|
State: child.getState(),
|
||||||
Pid: int32(child.cmd.Process.Pid),
|
Pid: int32(child.cmd.Process.Pid),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -283,7 +299,7 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
var newprocs []*procmeta
|
var newprocs []*procmeta
|
||||||
for _, proc := range hc.childProcs {
|
for _, proc := range hc.childProcs {
|
||||||
if proc.cmd == exited {
|
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) {
|
go func(proc *procmeta) {
|
||||||
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||||
proc.cmd.Process.Signal(os.Kill)
|
proc.cmd.Process.Signal(os.Kill)
|
||||||
@ -291,7 +307,7 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
proc.cmd.Wait()
|
proc.cmd.Wait()
|
||||||
proc.cmd.Process.Release()
|
proc.cmd.Process.Release()
|
||||||
|
|
||||||
if proc.state == protos.ProcessState_Restart {
|
if proc.isState(protos.ProcessState_Restart) {
|
||||||
hc.startChildProcess(&shared.StartProcessRequest{
|
hc.startChildProcess(&shared.StartProcessRequest{
|
||||||
Version: proc.version,
|
Version: proc.version,
|
||||||
Name: proc.name,
|
Name: proc.name,
|
||||||
@ -407,6 +423,30 @@ func NewClient(standalone bool) (HoustonClient, error) {
|
|||||||
if err := hc.uploadFiles(&ur); err != nil {
|
if err := hc.uploadFiles(&ur); err != nil {
|
||||||
logger.Println(err)
|
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 {
|
for _, proc := range hc.childProcs {
|
||||||
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||||
proc.cmd.Process.Signal(os.Kill)
|
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() {
|
if err == nil && fi.IsDir() {
|
||||||
exefile := "./" + path.Clean(strings.TrimPrefix(req.Args[0], "/"))
|
exefile := "./" + path.Clean(strings.TrimPrefix(req.Args[0], "/"))
|
||||||
err = set_permission(path.Join(verpath, exefile))
|
os.Chmod(path.Join(verpath, exefile), 0777)
|
||||||
if err != nil {
|
|
||||||
logger.Println("set_permission failed :", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
exef, _ := os.Executable()
|
exef, _ := os.Executable()
|
||||||
cmd := exec.Command(path.Join(path.Dir(exef), verpath, exefile), req.Args[1:]...)
|
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
|
cmd.Dir = verpath
|
||||||
stdin, _ := cmd.StdinPipe()
|
stdin, _ := cmd.StdinPipe()
|
||||||
|
|
||||||
|
seq++
|
||||||
return &procmeta{
|
return &procmeta{
|
||||||
|
id: seq,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
name: req.Name,
|
name: req.Name,
|
||||||
args: req.Args,
|
args: req.Args,
|
||||||
version: req.Version,
|
version: req.Version,
|
||||||
state: protos.ProcessState_Stopped,
|
state: int32(protos.ProcessState_Stopped),
|
||||||
stdin: stdin,
|
stdin: stdin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,6 +240,17 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
var metricBuffer []byte
|
var metricBuffer []byte
|
||||||
metricValues := make(map[string]metricValueAccessor)
|
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 {
|
for {
|
||||||
buff, err := reader.ReadBytes('\n')
|
buff, err := reader.ReadBytes('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -319,11 +334,11 @@ func (hc *houstonClient) launch(meta *procmeta) error {
|
|||||||
go stdReader(meta.name, stdout)
|
go stdReader(meta.name, stdout)
|
||||||
|
|
||||||
logger.Println("startChildProcess :", meta.cmd.Args)
|
logger.Println("startChildProcess :", meta.cmd.Args)
|
||||||
|
|
||||||
err = meta.cmd.Start()
|
err = meta.cmd.Start()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
meta.state = protos.ProcessState_Running
|
meta.setState(protos.ProcessState_Running)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +404,7 @@ func (hc *houstonClient) stopChildProcess(req *shared.StopProcessRequest, op pro
|
|||||||
var remains []*procmeta
|
var remains []*procmeta
|
||||||
var killing []*procmeta
|
var killing []*procmeta
|
||||||
for _, proc := range hc.childProcs {
|
for _, proc := range hc.childProcs {
|
||||||
if proc.state != protos.ProcessState_Running {
|
if !proc.isState(protos.ProcessState_Running) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +434,7 @@ func (hc *houstonClient) stopChildProcess(req *shared.StopProcessRequest, op pro
|
|||||||
|
|
||||||
if len(killing) > 0 {
|
if len(killing) > 0 {
|
||||||
for _, proc := range killing {
|
for _, proc := range killing {
|
||||||
proc.state = protos.ProcessState_Stopping
|
proc.setState(protos.ProcessState_Stopping)
|
||||||
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
if err := proc.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||||
proc.cmd.Process.Signal(os.Kill)
|
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())
|
op.Refresh(context.Background(), hc.makeOperationQueryRequest())
|
||||||
hc.exitChan <- proc.cmd
|
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
|
golang.org/x/text v0.10.0
|
||||||
google.golang.org/grpc v1.56.0
|
google.golang.org/grpc v1.56.0
|
||||||
google.golang.org/protobuf v1.31.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 (
|
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=
|
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 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
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-20231123110857-d672b5dd90ec h1:hB0bjNdS/5xClLR/vhPcACLRbpuxaLiCRwH6PV4a6EU=
|
||||||
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/go.mod h1:XvklTTSvQX5uviivGBcZo8eIL+mV94W2e4uBBXcT5JY=
|
||||||
|
|||||||
@ -17,6 +17,7 @@ const (
|
|||||||
Restart = Operation("restart")
|
Restart = Operation("restart")
|
||||||
Stop = Operation("stop")
|
Stop = Operation("stop")
|
||||||
Upload = Operation("upload")
|
Upload = Operation("upload")
|
||||||
|
Exception = Operation("exception")
|
||||||
)
|
)
|
||||||
|
|
||||||
type DeployRequest struct {
|
type DeployRequest struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user