limit run command to single instance
parent
091c026a46
commit
eddd813846
|
@ -36,12 +36,15 @@ var Ext2Mode map[string]string = map[string]string{
|
|||
type Action struct {
|
||||
Name string `json:"name"`
|
||||
Cmd string `json:"cmd"`
|
||||
run chan struct{} `json:"-"`
|
||||
pid int `json:"-"`
|
||||
}
|
||||
|
||||
type Integration struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Cmd func() (string, error) `json:"-"`
|
||||
run chan struct{} `json:"-"`
|
||||
}
|
||||
|
||||
type ConfigUI struct {
|
||||
|
|
32
file.go
32
file.go
|
@ -1,7 +1,9 @@
|
|||
package configui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
|
@ -25,6 +27,8 @@ type File struct {
|
|||
|
||||
lock sync.RWMutex `json:"-"`
|
||||
owner *ConfigUI `json:"-"`
|
||||
run chan struct{} `json:"-"`
|
||||
pid int `json:"-"`
|
||||
}
|
||||
|
||||
func (f *File) Read() ([]byte, error) {
|
||||
|
@ -57,6 +61,20 @@ func (f *File) Do(CmdTimeout time.Duration) (string, error) {
|
|||
}
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
// limit running instance to 1
|
||||
if cap(f.run) == 0 {
|
||||
f.run = make(chan struct{}, 1)
|
||||
}
|
||||
select {
|
||||
case f.run <- struct{}{}:
|
||||
defer func() { <-f.run }()
|
||||
default:
|
||||
f.owner.log.Error("task is running: ", f.Name)
|
||||
return "", fmt.Errorf("another task of %s is running with pid: %d", f.Name, f.pid)
|
||||
}
|
||||
|
||||
// prepare cmd
|
||||
cmd := &exec.Cmd{}
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd = exec.Command(WIN_SHELL, "/c", f.Action)
|
||||
|
@ -66,12 +84,14 @@ func (f *File) Do(CmdTimeout time.Duration) (string, error) {
|
|||
f.owner.log.Info("DO: ", f.Action)
|
||||
done := make(chan string, 1)
|
||||
go func() {
|
||||
out, _ := cmd.CombinedOutput()
|
||||
// real cmd err is unhandled, but passed to client
|
||||
// if err != nil {
|
||||
// return string(out), err
|
||||
// }
|
||||
done <- string(out)
|
||||
|
||||
var b bytes.Buffer
|
||||
cmd.Stdout = &b
|
||||
cmd.Stderr = &b
|
||||
cmd.Start()
|
||||
f.pid = cmd.Process.Pid
|
||||
cmd.Wait()
|
||||
done <- b.String()
|
||||
}()
|
||||
select {
|
||||
case <-time.After(CmdTimeout):
|
||||
|
|
33
handler.go
33
handler.go
|
@ -8,6 +8,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"kumoly.io/lib/ksrv"
|
||||
)
|
||||
|
@ -130,9 +131,25 @@ func (cui *ConfigUI) Apply(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (cui *ConfigUI) DoAction(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Query().Get("name")
|
||||
for _, v := range cui.Actions {
|
||||
for i, v := range cui.Actions {
|
||||
if v.Name == name {
|
||||
|
||||
// limit running instance to one
|
||||
if cap(cui.Actions[i].run) != 1 {
|
||||
cui.Actions[i].run = make(chan struct{}, 1)
|
||||
}
|
||||
select {
|
||||
case cui.Actions[i].run <- struct{}{}:
|
||||
defer func() { <-cui.Actions[i].run }()
|
||||
default:
|
||||
panic(fmt.Errorf("another task of %s is running with pid: %d", name, v.pid))
|
||||
}
|
||||
|
||||
file := &File{Name: name, Action: v.Cmd, owner: cui}
|
||||
go func() {
|
||||
<-time.After(time.Millisecond * 10)
|
||||
cui.Actions[i].pid = file.pid
|
||||
}()
|
||||
result, err := file.Do(cui.cmdTimeout)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -146,8 +163,20 @@ func (cui *ConfigUI) DoAction(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (cui *ConfigUI) DoIntegration(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Query().Get("name")
|
||||
for _, v := range cui.Integrations {
|
||||
for i, v := range cui.Integrations {
|
||||
if v.Name == name {
|
||||
|
||||
// limit running instance to one
|
||||
if cap(cui.Integrations[i].run) != 1 {
|
||||
cui.Integrations[i].run = make(chan struct{}, 1)
|
||||
}
|
||||
select {
|
||||
case cui.Integrations[i].run <- struct{}{}:
|
||||
defer func() { <-cui.Integrations[i].run }()
|
||||
default:
|
||||
panic(fmt.Errorf("another task of %s is running", name))
|
||||
}
|
||||
|
||||
result, err := v.Cmd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
Loading…
Reference in New Issue