diff --git a/fsm.go b/fsm.go index 87d04db..98239cb 100644 --- a/fsm.go +++ b/fsm.go @@ -145,7 +145,7 @@ func (p *Process) waitNextRetry() { p.retryLeft -= 1 select { case <-time.After(2 * time.Second): // TODO: need put it into Program - go p.Operate(StartEvent) + p.startCommand() case <-p.stopC: p.stopCommand() } @@ -162,42 +162,51 @@ func (p *Process) IsRunning() bool { return p.State() == Running || p.State() == RetryWait } +func (p *Process) startCommand() { + p.cmd = kexec.CommandString("echo hello world && sleep 4 && echo end") + p.cmd.Stdout = os.Stdout + + p.SetState(Running) + go func() { + errC := GoFunc(p.cmd.Run) + startTime := time.Now() + select { + case err := <-errC: //<-GoTimeoutFunc(time.Duration(p.StartSeconds)*time.Second, p.cmd.Run): + log.Println(err, time.Since(startTime)) + if time.Since(startTime) < time.Duration(p.StartSeconds)*time.Second { + if p.retryLeft == p.StartRetries { // If first time quit so fast, just set to fatal + p.SetState(Fatal) + log.Println("Start change to fatal") + return + } + } + p.waitNextRetry() + case <-p.stopC: + p.stopCommand() + } + }() +} + func NewProcess(pg Program) *Process { pr := &Process{ FSM: NewFSM(Stopped), Program: pg, stopC: make(chan int), retryLeft: pg.StartRetries, + Status: string(Stopped), } pr.StateChange = func(_, newStatus FSMState) { pr.Status = string(newStatus) } - - startFunc := func() { - pr.retryLeft = pr.StartRetries - pr.cmd = kexec.CommandString("echo hello world && sleep 10 && echo end") - pr.cmd.Stdout = os.Stdout - - pr.SetState(Running) - go func() { - errC := GoFunc(pr.cmd.Run) - startTime := time.Now() - select { - case err := <-errC: //<-GoTimeoutFunc(time.Duration(pr.StartSeconds)*time.Second, pr.cmd.Run): - log.Println(err) - if time.Since(startTime) < time.Duration(pr.StartSeconds) { - pr.SetState(Fatal) - return - } - pr.waitNextRetry() - case <-pr.stopC: - pr.stopCommand() - } - }() + if pr.StartSeconds <= 0 { + pr.StartSeconds = 3 } - pr.AddHandler(Stopped, StartEvent, startFunc) - pr.AddHandler(Fatal, StartEvent, startFunc) + pr.AddHandler(Stopped, StartEvent, func() { + pr.retryLeft = pr.StartRetries + pr.startCommand() + }) + pr.AddHandler(Fatal, StartEvent, pr.startCommand) pr.AddHandler(Running, StopEvent, func() { pr.cmd.Terminate(syscall.SIGKILL) diff --git a/res/index.html b/res/index.html index d8a793c..bdf47f4 100644 --- a/res/index.html +++ b/res/index.html @@ -5,7 +5,7 @@ gosuv - + @@ -43,6 +43,9 @@ +
@@ -58,15 +61,18 @@ @@ -82,6 +88,9 @@ + @@ -144,12 +153,12 @@ // keyboard: false, backdrop: 'static', }) - }) - $("#newProgram").modal({ - show: true, - // keyboard: false, - backdrop: 'static', - }) + }); + // $("#newProgram").modal({ + // show: true, + // // keyboard: false, + // backdrop: 'static', + // }) }); diff --git a/res/js/index.js b/res/js/index.js index 0dfeb79..60a331a 100644 --- a/res/js/index.js +++ b/res/js/index.js @@ -56,6 +56,25 @@ var vm = new Vue({ } return this.breadcrumb; }, + refresh: function() { + console.log("RR"); + $.ajax({ + url: "/api/programs", + success: function(data) { + vm.programs = data; + } + }); + }, + cmdStart: function(name) { + console.log(name); + $.ajax({ + url: "/api/programs/" + name + "/start", + method: 'post', + success: function(data) { + console.log(data); + } + }) + }, } }) @@ -72,18 +91,12 @@ Vue.filter('formatBytes', function(value) { else return (bytes / 1073741824).toFixed(1) + " GB"; }) -var refreshPrograms = function() { - $.ajax({ - url: "/api/programs", - success: function(data) { - console.log(data) - vm.programs = data; - } - }); -} +Vue.directive('disable', function(value) { + this.el.disabled = !!value +}) $(function() { - refreshPrograms(); + vm.refresh(); $("#formNewProgram").submit(function(e) { var url = "/api/programs", diff --git a/web.go b/web.go index 0132353..998a983 100644 --- a/web.go +++ b/web.go @@ -31,7 +31,6 @@ func (s *Supervisor) programPath() string { func (s *Supervisor) addOrUpdateProgram(pg Program) error { origPg, ok := s.pgMap[pg.Name] if ok { - // log.Println("Orig:", origPg, "Curr:", pg) if !reflect.DeepEqual(origPg, &pg) { log.Println("Update:", pg.Name) origProc := s.procMap[pg.Name] @@ -181,6 +180,26 @@ func (s *Supervisor) hAddProgram(w http.ResponseWriter, r *http.Request) { w.Write(data) } +func (s *Supervisor) hStartProgram(w http.ResponseWriter, r *http.Request) { + log.Println("Hello") + name := mux.Vars(r)["name"] + proc, ok := s.procMap[name] + var data []byte + if !ok { + data, _ = json.Marshal(map[string]interface{}{ + "status": 1, + "error": fmt.Sprintf("Process %s not exists", strconv.Quote(name)), + }) + } else { + proc.Operate(StartEvent) + data, _ = json.Marshal(map[string]interface{}{ + "status": 0, + "name": name, + }) + } + w.Write(data) +} + func init() { suv := &Supervisor{ ConfigDir: filepath.Join(UserHomeDir(), ".gosuv"), @@ -194,6 +213,7 @@ func init() { r.HandleFunc("/", suv.hIndex) r.HandleFunc("/api/programs", suv.hGetProgram).Methods("GET") r.HandleFunc("/api/programs", suv.hAddProgram).Methods("POST") + r.HandleFunc("/api/programs/{name}/start", suv.hStartProgram).Methods("POST") fs := http.FileServer(http.Dir("res")) http.Handle("/", r)
- - +