Refactor interrupt monitoring and shutdown

This makes it so that the same goroutine responsible for starting
processes shuts them down. This is a stepping stone to a larger refactor
whose goal is to eliminate race conditions.
This commit is contained in:
Peter Waller
2014-05-21 08:37:21 +01:00
parent c3001f4941
commit 9c2bf670ca
3 changed files with 39 additions and 27 deletions
+39 -23
View File
@@ -20,8 +20,6 @@ var flagRestart bool
var shutdownNow bool
var processes = map[string]*Process{}
var shutdown_mutex = new(sync.Mutex)
var wg sync.WaitGroup
var cmdStart = &Command{
Run: runStart,
@@ -74,10 +72,13 @@ func parseConcurrency(value string) (map[string]int, error) {
return concurrency, nil
}
func startProcess(idx, procNum int, proc ProcfileEntry, env Env, of *OutletFactory) {
shutdown_mutex.Lock()
defer shutdown_mutex.Unlock()
type Forego struct {
shutdown sync.Once
teardown chan struct{} // barrier: closed when shutting down
wg sync.WaitGroup
}
func (f *Forego) startProcess(idx, procNum int, proc ProcfileEntry, env Env, of *OutletFactory) {
port := flagPort + (idx * 100)
ps := NewProcess(proc.Command, env)
@@ -92,22 +93,41 @@ func startProcess(idx, procNum int, proc ProcfileEntry, env Env, of *OutletFacto
of.SystemOutput(fmt.Sprintf("starting %s on port %d", procName, port))
wg.Add(1)
f.wg.Add(1)
go func(proc ProcfileEntry, ps *Process) {
defer wg.Done()
defer f.wg.Done()
ps.Wait()
if flagRestart && !shutdownNow {
delete(processes, proc.Name)
startProcess(idx, procNum, proc, env, of)
f.startProcess(idx, procNum, proc, env, of)
return
}
delete(processes, proc.Name)
ShutdownProcesses(of)
f.SignalShutdown()
}(proc, ps)
}
func (f *Forego) SignalShutdown() {
f.shutdown.Do(func() {
close(f.teardown)
})
}
func (f *Forego) monitorInterrupt() {
handler := make(chan os.Signal, 1)
signal.Notify(handler, os.Interrupt)
for sig := range handler {
switch sig {
case os.Interrupt:
fmt.Println(" | ctrl-c detected")
f.SignalShutdown()
}
}
}
func runStart(cmd *Command, args []string) {
root := filepath.Dir(flagProcfile)
@@ -127,19 +147,11 @@ func runStart(cmd *Command, args []string) {
of := NewOutletFactory()
of.Padding = pf.LongestProcessName()
handler := make(chan os.Signal, 1)
signal.Notify(handler, os.Interrupt)
f := &Forego{
teardown: make(chan struct{}),
}
go func() {
for sig := range handler {
switch sig {
case os.Interrupt:
shutdownNow = true
fmt.Println(" | ctrl-c detected")
go func() { ShutdownProcesses(of) }()
}
}
}()
go f.monitorInterrupt()
var singleton string = ""
if len(args) > 0 {
@@ -156,10 +168,14 @@ func runStart(cmd *Command, args []string) {
}
for i := 0; i < numProcs; i++ {
if (singleton == "") || (singleton == proc.Name) {
startProcess(idx, i, proc, env, of)
f.startProcess(idx, i, proc, env, of)
}
}
}
wg.Wait()
<-f.teardown
of.SystemOutput("shutting down")
ShutdownProcesses(of)
f.wg.Wait()
}
-2
View File
@@ -34,8 +34,6 @@ func (p *Process) Signal(signal syscall.Signal) {
}
func ShutdownProcesses(of *OutletFactory) {
shutdown_mutex.Lock()
of.SystemOutput("shutting down")
for name, ps := range processes {
of.SystemOutput(fmt.Sprintf("sending SIGTERM to %s", name))
ps.Signal(syscall.SIGTERM)
-2
View File
@@ -26,8 +26,6 @@ func (p *Process) Signal(signal syscall.Signal) {
}
func ShutdownProcesses(of *OutletFactory) {
shutdown_mutex.Lock()
of.SystemOutput("shutting down")
for name, ps := range processes {
of.SystemOutput(fmt.Sprintf("terminating %s", name))
ps.cmd.Process.Signal(os.Kill)