supervise: refactor to use one HTTP handler

This commit is contained in:
Michael Stapelberg 2018-06-25 18:27:23 +02:00
parent 9a14ab0d8d
commit 7dc7a36757

View File

@ -105,6 +105,15 @@ func (s *service) Process() *os.Process {
return s.process return s.process
} }
func (s *service) Signal(signal syscall.Signal) error {
s.processMu.RLock()
defer s.processMu.RUnlock()
if s.process != nil {
return s.process.Signal(signal)
}
return nil // no process, nothing to signal
}
func (s *service) setProcess(p *os.Process) { func (s *service) setProcess(p *os.Process) {
s.processMu.Lock() s.processMu.Lock()
defer s.processMu.Unlock() defer s.processMu.Unlock()
@ -195,35 +204,11 @@ func supervise(s *service) {
} }
} }
func redirectToStatus(w http.ResponseWriter, r *http.Request, path string) { var services []*service
// StatusSeeOther will result in a GET request for the
// redirect location
u, _ := url.Parse("/status")
u.RawQuery = url.Values{
"path": []string{path},
}.Encode()
http.Redirect(w, r, u.String(), http.StatusSeeOther)
}
// killSupervisedServices is called before rebooting when upgrading, allowing // killSupervisedServices is called before rebooting when upgrading, allowing
// processes to terminate in an orderly fashion. // processes to terminate in an orderly fashion.
var killSupervisedServices = func() {} func killSupervisedServices() {
func superviseServices(services []*service) {
for _, s := range services {
go supervise(s)
}
findSvc := func(path string) *service {
for _, s := range services {
if s.cmd.Path == path {
return s
}
}
return nil
}
killSupervisedServices = func() {
for _, s := range services { for _, s := range services {
if s.Stopped() { if s.Stopped() {
continue continue
@ -235,39 +220,36 @@ func superviseServices(services []*service) {
p.Signal(syscall.SIGTERM) p.Signal(syscall.SIGTERM)
} }
} }
}
func findSvc(path string) *service {
for _, s := range services {
if s.cmd.Path == path {
return s
}
}
return nil
}
func restart(s *service, signal syscall.Signal) error {
if s.Stopped() {
s.setStopped(false) // start process in next supervise iteration
return nil
} }
http.HandleFunc("/stop", func(w http.ResponseWriter, r *http.Request) { return s.Signal(signal) // kill to restart
if r.Method != http.MethodPost { }
http.Error(w, "expected a POST request", http.StatusBadRequest)
return
}
path := r.FormValue("path") func stop(s *service, signal syscall.Signal) error {
if s.Stopped() {
s := findSvc(path) return nil // nothing to do
if s == nil || s.Stopped() {
redirectToStatus(w, r, path)
return
} }
s.setStopped(true) s.setStopped(true)
return s.Signal(signal)
}
p := s.Process() func stopstartHandler(w http.ResponseWriter, r *http.Request) {
if p == nil {
redirectToStatus(w, r, path)
return
}
if err := p.Signal(syscall.SIGTERM); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
redirectToStatus(w, r, path)
})
http.HandleFunc("/restart", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
http.Error(w, "expected a POST request", http.StatusBadRequest) http.Error(w, "expected a POST request", http.StatusBadRequest)
return return
@ -279,30 +261,36 @@ func superviseServices(services []*service) {
} }
path := r.FormValue("path") path := r.FormValue("path")
s := findSvc(path) s := findSvc(path)
if s == nil { if s == nil {
redirectToStatus(w, r, path) http.Error(w, "no such service", http.StatusNotFound)
return return
} }
var err error
if s.Stopped() { if r.URL.Path == "/restart" {
s.setStopped(false) err = restart(s, signal)
redirectToStatus(w, r, path) } else {
return err = stop(s, signal)
} }
if err != nil {
p := s.Process()
if p == nil {
redirectToStatus(w, r, path)
return
}
if err := p.Signal(signal); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
// StatusSeeOther will result in a GET request for the
redirectToStatus(w, r, path) // redirect location
}) u, _ := url.Parse("/status")
u.RawQuery = url.Values{
"path": []string{path},
}.Encode()
http.Redirect(w, r, u.String(), http.StatusSeeOther)
}
func superviseServices(svc []*service) {
services = svc
for _, s := range services {
go supervise(s)
}
http.HandleFunc("/stop", stopstartHandler)
http.HandleFunc("/restart", stopstartHandler)
} }