Skip to content

Commit

Permalink
Merge branch 'packagize_supervisor' into mackerel-agent_safe
Browse files Browse the repository at this point in the history
  • Loading branch information
Songmu committed Feb 21, 2017
2 parents 0cb5e85 + 02d373e commit c29ef61
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 67 deletions.
9 changes: 5 additions & 4 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/mackerelio/mackerel-agent/command"
"github.com/mackerelio/mackerel-agent/config"
"github.com/mackerelio/mackerel-agent/mackerel"
"github.com/mackerelio/mackerel-agent/supervisor"
"github.com/mackerelio/mackerel-agent/version"
)

Expand Down Expand Up @@ -78,10 +79,10 @@ func doSupervise(fs *flag.FlagSet, argv []string) error {
}
defer removePidFile(conf.Pidfile)

return (&supervisor{
prog: os.Args[0],
argv: copiedArgv,
}).supervise(nil)
return (&supervisor.Supervisor{
Prog: os.Args[0],
Argv: copiedArgv,
}).Supervise(nil)
}

/* +command version - display version of mackerel-agent
Expand Down
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/mackerelio/mackerel-agent/command"
"github.com/mackerelio/mackerel-agent/config"
"github.com/mackerelio/mackerel-agent/logging"
"github.com/mackerelio/mackerel-agent/util"
"github.com/mackerelio/mackerel-agent/version"
"github.com/motemen/go-cli"
)
Expand Down Expand Up @@ -165,7 +166,7 @@ func createPidFile(pidfile string) error {
}
if pidString, err := ioutil.ReadFile(pidfile); err == nil {
if pid, err := strconv.Atoi(string(pidString)); err == nil {
if existsPid(pid) {
if util.ExistsPid(pid) {
return fmt.Errorf("pidfile found, try stopping another running mackerel-agent or delete %s", pidfile)
}
// Note mackerel-agent in windows can't remove pidfile during stoping the service
Expand Down
52 changes: 29 additions & 23 deletions supervisor.go → supervisor/supervisor.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package supervisor

import (
"bytes"
Expand All @@ -9,11 +9,16 @@ import (
"sync"
"syscall"
"time"

"github.com/mackerelio/mackerel-agent/logging"
)

type supervisor struct {
prog string
argv []string
var logger = logging.GetLogger("supervisor")

// Supervisor supervise the mackerel-agent
type Supervisor struct {
Prog string
Argv []string

cmd *exec.Cmd
startAt time.Time
Expand All @@ -26,37 +31,37 @@ type supervisor struct {
huppedMu sync.RWMutex
}

func (sv *supervisor) setSignaled(signaled bool) {
func (sv *Supervisor) setSignaled(signaled bool) {
sv.signaledMu.Lock()
defer sv.signaledMu.Unlock()
sv.signaled = signaled
}

func (sv *supervisor) getSignaled() bool {
func (sv *Supervisor) getSignaled() bool {
sv.signaledMu.RLock()
defer sv.signaledMu.RUnlock()
return sv.signaled
}

func (sv *supervisor) setHupped(hupped bool) {
func (sv *Supervisor) setHupped(hupped bool) {
sv.huppedMu.Lock()
defer sv.huppedMu.Unlock()
sv.hupped = hupped
}

func (sv *supervisor) getHupped() bool {
func (sv *Supervisor) getHupped() bool {
sv.huppedMu.RLock()
defer sv.huppedMu.RUnlock()
return sv.hupped
}

func (sv *supervisor) getCmd() *exec.Cmd {
func (sv *Supervisor) getCmd() *exec.Cmd {
sv.mu.RLock()
defer sv.mu.RUnlock()
return sv.cmd
}

func (sv *supervisor) getStartAt() time.Time {
func (sv *Supervisor) getStartAt() time.Time {
sv.mu.RLock()
defer sv.mu.RUnlock()
return sv.startAt
Expand All @@ -66,19 +71,19 @@ func (sv *supervisor) getStartAt() time.Time {
// and terminate the process without crash recovery
var spawnInterval = 30 * time.Second

func (sv *supervisor) launched() bool {
func (sv *Supervisor) launched() bool {
return sv.getCmd().Process != nil && time.Now().After(sv.getStartAt().Add(spawnInterval))
}

func (sv *supervisor) buildCmd() *exec.Cmd {
argv := append(sv.argv, "-child")
cmd := exec.Command(sv.prog, argv...)
func (sv *Supervisor) buildCmd() *exec.Cmd {
argv := append(sv.Argv, "-child")
cmd := exec.Command(sv.Prog, argv...)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
return cmd
}

func (sv *supervisor) start() error {
func (sv *Supervisor) start() error {
sv.mu.Lock()
sv.setHupped(false)
defer sv.mu.Unlock()
Expand All @@ -87,14 +92,14 @@ func (sv *supervisor) start() error {
return sv.cmd.Start()
}

func (sv *supervisor) stop(sig os.Signal) error {
func (sv *Supervisor) stop(sig os.Signal) error {
sv.setSignaled(true)
return sv.getCmd().Process.Signal(sig)
}

func (sv *supervisor) configtest() error {
argv := append([]string{"configtest"}, sv.argv...)
cmd := exec.Command(sv.prog, argv...)
func (sv *Supervisor) configtest() error {
argv := append([]string{"configtest"}, sv.Argv...)
cmd := exec.Command(sv.Prog, argv...)
buf := &bytes.Buffer{}
cmd.Stderr = buf
err := cmd.Run()
Expand All @@ -104,7 +109,7 @@ func (sv *supervisor) configtest() error {
return nil
}

func (sv *supervisor) reload() error {
func (sv *Supervisor) reload() error {
err := sv.configtest()
if err != nil {
return err
Expand All @@ -113,7 +118,7 @@ func (sv *supervisor) reload() error {
return sv.getCmd().Process.Signal(syscall.SIGTERM)
}

func (sv *supervisor) wait() (err error) {
func (sv *Supervisor) wait() (err error) {
for {
err = sv.cmd.Wait()
if sv.getSignaled() || (!sv.getHupped() && !sv.launched()) {
Expand All @@ -130,7 +135,7 @@ func (sv *supervisor) wait() (err error) {
return
}

func (sv *supervisor) handleSignal(ch <-chan os.Signal) {
func (sv *Supervisor) handleSignal(ch <-chan os.Signal) {
for sig := range ch {
if sig == syscall.SIGHUP {
logger.Infof("receiving HUP, spawning a new mackerel-agent")
Expand All @@ -144,7 +149,8 @@ func (sv *supervisor) handleSignal(ch <-chan os.Signal) {
}
}

func (sv *supervisor) supervise(c chan os.Signal) error {
// Supervise the mackerel-agent
func (sv *Supervisor) Supervise(c chan os.Signal) error {
err := sv.start()
if err != nil {
return err
Expand Down
68 changes: 35 additions & 33 deletions supervisor_test.go → supervisor/supervisor_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// +build !windows

package main
package supervisor

import (
"os"
"os/exec"
"syscall"
"testing"
"time"

"github.com/mackerelio/mackerel-agent/util"
)

const stubAgent = "testdata/stub-agent"
Expand All @@ -20,18 +22,18 @@ func init() {
}

func TestSupervisor(t *testing.T) {
sv := &supervisor{
prog: stubAgent,
argv: []string{"dummy"},
sv := &Supervisor{
Prog: stubAgent,
Argv: []string{"dummy"},
}
ch := make(chan os.Signal, 1)
done := make(chan error)
go func() {
done <- sv.supervise(ch)
done <- sv.Supervise(ch)
}()
time.Sleep(50 * time.Millisecond)
pid := sv.getCmd().Process.Pid
if !existsPid(pid) {
if !util.ExistsPid(pid) {
t.Errorf("process doesn't exist")
}
time.Sleep(50 * time.Millisecond)
Expand All @@ -41,24 +43,24 @@ func TestSupervisor(t *testing.T) {
if err != nil {
t.Errorf("error should be nil but: %v", err)
}
if existsPid(pid) {
if util.ExistsPid(pid) {
t.Errorf("child process isn't terminated")
}
}

func TestSupervisor_reload(t *testing.T) {
sv := &supervisor{
prog: stubAgent,
argv: []string{"dummy"},
sv := &Supervisor{
Prog: stubAgent,
Argv: []string{"dummy"},
}
ch := make(chan os.Signal, 1)
done := make(chan error)
go func() {
done <- sv.supervise(ch)
done <- sv.Supervise(ch)
}()
time.Sleep(50 * time.Millisecond)
oldPid := sv.getCmd().Process.Pid
if !existsPid(oldPid) {
if !util.ExistsPid(oldPid) {
t.Errorf("process doesn't exist")
}
ch <- syscall.SIGHUP
Expand All @@ -67,10 +69,10 @@ func TestSupervisor_reload(t *testing.T) {
if oldPid == newPid {
t.Errorf("reload failed")
}
if existsPid(oldPid) {
if util.ExistsPid(oldPid) {
t.Errorf("old process isn't terminated")
}
if !existsPid(newPid) {
if !util.ExistsPid(newPid) {
t.Errorf("new process doesn't exist")
}
ch <- syscall.SIGTERM
Expand All @@ -81,24 +83,24 @@ func TestSupervisor_reload(t *testing.T) {
if newPid != sv.getCmd().Process.Pid {
t.Errorf("something went wrong")
}
if existsPid(newPid) {
if util.ExistsPid(newPid) {
t.Errorf("child process isn't terminated")
}
}

func TestSupervisor_reloadFail(t *testing.T) {
sv := &supervisor{
prog: stubAgent,
argv: []string{"failed"},
sv := &Supervisor{
Prog: stubAgent,
Argv: []string{"failed"},
}
ch := make(chan os.Signal, 1)
done := make(chan error)
go func() {
done <- sv.supervise(ch)
done <- sv.Supervise(ch)
}()
time.Sleep(50 * time.Millisecond)
oldPid := sv.getCmd().Process.Pid
if !existsPid(oldPid) {
if !util.ExistsPid(oldPid) {
t.Errorf("process doesn't exist")
}
ch <- syscall.SIGHUP
Expand All @@ -113,25 +115,25 @@ func TestSupervisor_reloadFail(t *testing.T) {
}

func TestSupervisor_launchFailed(t *testing.T) {
sv := &supervisor{
prog: stubAgent,
argv: []string{"launch failure"},
sv := &Supervisor{
Prog: stubAgent,
Argv: []string{"launch failure"},
}
ch := make(chan os.Signal, 1)
done := make(chan error)
go func() {
done <- sv.supervise(ch)
done <- sv.Supervise(ch)
}()
time.Sleep(50 * time.Millisecond)
pid := sv.getCmd().Process.Pid
if !existsPid(pid) {
if !util.ExistsPid(pid) {
t.Errorf("process doesn't exist")
}
err := <-done
if err == nil {
t.Errorf("something went wrong")
}
if existsPid(sv.getCmd().Process.Pid) {
if util.ExistsPid(sv.getCmd().Process.Pid) {
t.Errorf("child process isn't terminated")
}
}
Expand All @@ -141,18 +143,18 @@ func TestSupervisor_crashRecovery(t *testing.T) {
spawnInterval = 300 * time.Millisecond
defer func() { spawnInterval = origSpawnInterval }()

sv := &supervisor{
prog: stubAgent,
argv: []string{"blah blah blah"},
sv := &Supervisor{
Prog: stubAgent,
Argv: []string{"blah blah blah"},
}
ch := make(chan os.Signal, 1)
done := make(chan error)
go func() {
done <- sv.supervise(ch)
done <- sv.Supervise(ch)
}()
time.Sleep(50 * time.Millisecond)
oldPid := sv.getCmd().Process.Pid
if !existsPid(oldPid) {
if !util.ExistsPid(oldPid) {
t.Errorf("process doesn't exist")
}
time.Sleep(spawnInterval)
Expand All @@ -165,10 +167,10 @@ func TestSupervisor_crashRecovery(t *testing.T) {
if oldPid == newPid {
t.Errorf("crash recovery failed")
}
if existsPid(oldPid) {
if util.ExistsPid(oldPid) {
t.Errorf("old process isn't terminated")
}
if !existsPid(newPid) {
if !util.ExistsPid(newPid) {
t.Errorf("new process doesn't exist")
}
ch <- syscall.SIGTERM
Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions util/pid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package util

// ExistsPid check if pid exists
func ExistsPid(pid int) bool {
return existsPid(pid)
}
2 changes: 1 addition & 1 deletion pid_darwin.go → util/pid_darwin.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package util

import (
"fmt"
Expand Down
Loading

0 comments on commit c29ef61

Please sign in to comment.