mirror of
https://github.com/wahyd4/forego.git
synced 2026-08-09 05:07:05 +10:00
signal management, system messages
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/daviddengcn/go-colortext"
|
||||
"github.com/kr/pretty"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -36,7 +37,7 @@ func (o *Outlet) Write(b []byte) (num int, err error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(b))
|
||||
for scanner.Scan() {
|
||||
formatter := fmt.Sprintf("%%-%ds | ", LongestOutletName())
|
||||
ct.ChangeColor(o.Color, true, ct.None, true)
|
||||
ct.ChangeColor(o.Color, false, ct.None, false)
|
||||
fmt.Printf(formatter, o.Name)
|
||||
if (o.IsError) {
|
||||
ct.ChangeColor(ct.Red, true, ct.None, true)
|
||||
@@ -50,6 +51,10 @@ func (o *Outlet) Write(b []byte) (num int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ProcessOutput(w io.Writer, str string) {
|
||||
w.Write([]byte(str))
|
||||
}
|
||||
|
||||
var outlets = map[string]*Outlet{}
|
||||
|
||||
func createOutlet(name string, index int, isError bool) *Outlet {
|
||||
@@ -58,8 +63,8 @@ func createOutlet(name string, index int, isError bool) *Outlet {
|
||||
}
|
||||
|
||||
func LongestOutletName() (longest int) {
|
||||
// kr? better way to do this?
|
||||
longest = 0
|
||||
// kr?
|
||||
longest = 7 // foreman is the shortest name
|
||||
for name, _ := range outlets {
|
||||
if len(name) > longest {
|
||||
longest = len(name)
|
||||
@@ -67,3 +72,12 @@ func LongestOutletName() (longest int) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SystemOutput(str string) {
|
||||
ct.ChangeColor(ct.White, true, ct.None, true)
|
||||
formatter := fmt.Sprintf("%%-%ds | ", LongestOutletName())
|
||||
fmt.Printf(formatter, "foreman")
|
||||
ct.ResetColor()
|
||||
fmt.Println(str)
|
||||
ct.ResetColor()
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@ import (
|
||||
var procfileEntryRegexp = regexp.MustCompile("^([A-Za-z0-9_]+):\\s*(.+)$")
|
||||
|
||||
type ProcfileEntry struct {
|
||||
name string
|
||||
command string
|
||||
Name string
|
||||
Command string
|
||||
}
|
||||
|
||||
type Procfile struct {
|
||||
|
||||
@@ -10,12 +10,12 @@ var _ = fmt.Println // lol
|
||||
|
||||
func init() {
|
||||
handler := make(chan os.Signal, 1)
|
||||
fmt.Println("init")
|
||||
signal.Notify(handler, os.Interrupt)
|
||||
go func() {
|
||||
for sig := range handler {
|
||||
switch (sig) {
|
||||
case os.Interrupt:
|
||||
fmt.Println(" | ctrl-c detected, shutting down")
|
||||
ShutdownProcesses()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,19 +9,22 @@ import (
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const shutdownGraceTime = 1 * time.Second
|
||||
|
||||
var _ = pretty.Println // lol
|
||||
var _ = os.Stdout
|
||||
|
||||
var flagProcfile string
|
||||
var flagEnv string
|
||||
var flagPort int
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
var cmdStart = &Command{
|
||||
Run: runStart,
|
||||
Usage: "start [-f procfile] [-e env] [-c concurrency]",
|
||||
Usage: "start [-f procfile] [-e env] [-c concurrency] [-p port]",
|
||||
Short: "Start the application",
|
||||
Long: `
|
||||
Start the application specified by a Procfile (defaults to ./Procfile)
|
||||
@@ -38,6 +41,7 @@ var processes = map[string]*exec.Cmd{}
|
||||
func init() {
|
||||
cmdStart.Flag.StringVar(&flagProcfile, "f", "Procfile", "procfile")
|
||||
cmdStart.Flag.StringVar(&flagEnv, "e", "", "env")
|
||||
cmdStart.Flag.IntVar(&flagPort, "p", 5000, "port")
|
||||
}
|
||||
|
||||
func runStart(cmd *Command, args []string) {
|
||||
@@ -57,53 +61,40 @@ func runStart(cmd *Command, args []string) {
|
||||
|
||||
for idx, proc := range pf.entries {
|
||||
wg.Add(1)
|
||||
go func(idx int, proc ProcfileEntry) {
|
||||
command := []string{"/bin/bash", "-c", proc.command}
|
||||
var attr syscall.ProcAttr
|
||||
attr.Files = []uintptr{0,0,0}
|
||||
attr.Files[1] = uintptr(unsafe.Pointer(createOutlet(proc.name, idx, false)))
|
||||
attr.Files[2] = uintptr(unsafe.Pointer(createOutlet(proc.name, idx, true)))
|
||||
attr.Env = ps_env
|
||||
pid, err := syscall.ForkExec(command[0], command[1:], &attr)
|
||||
pretty.Println("arg0", command[0], "argv", command[1:])
|
||||
fmt.Println("pid", pid, "err", err)
|
||||
/* ps := exec.Command(command[0], command[1:]...)*/
|
||||
/* ps.Dir = root*/
|
||||
/* ps.Env = ps_env*/
|
||||
/* ps.Stdin = nil*/
|
||||
/* ps.Stdout = createOutlet(proc.name, idx, false)*/
|
||||
/* ps.Stderr = createOutlet(proc.name, idx, true)*/
|
||||
/* processes[proc.name] = ps*/
|
||||
/* ps.Start()*/
|
||||
/* syscall.Setpgid(ps.Process.Pid, -1 * ps.Process.Pid)*/
|
||||
fmt.Println("pid", pid)
|
||||
var wait syscall.WaitStatus
|
||||
var usage syscall.Rusage
|
||||
syscall.Wait4(pid, &wait, 0, &usage)
|
||||
fmt.Println("exitstatus", wait.ExitStatus())
|
||||
fmt.Println("process died")
|
||||
command := []string{"/bin/bash", "-c", proc.Command}
|
||||
ps := exec.Command(command[0], command[1:]...)
|
||||
port := flagPort + (idx * 100)
|
||||
processes[proc.Name] = ps
|
||||
ps.Dir = root
|
||||
ps.Env = append(ps_env, fmt.Sprintf("PORT=%d", port))
|
||||
ps.Stdin = nil
|
||||
ps.Stdout = createOutlet(proc.Name, idx, false)
|
||||
ps.Stderr = createOutlet(proc.Name, idx, true)
|
||||
ps.SysProcAttr = &syscall.SysProcAttr{}
|
||||
ps.SysProcAttr.Setsid = true
|
||||
ps.Start()
|
||||
SystemOutput(fmt.Sprintf("starting %s on port %d", proc.Name, port))
|
||||
go func(proc ProcfileEntry, ps *exec.Cmd) {
|
||||
ps.Wait()
|
||||
wg.Done()
|
||||
delete(processes, proc.name)
|
||||
}(idx, proc)
|
||||
delete(processes, proc.Name)
|
||||
}(proc, ps)
|
||||
}
|
||||
wg.Wait()
|
||||
fmt.Println("afterdone")
|
||||
}
|
||||
|
||||
func ShutdownProcesses() {
|
||||
for _, ps := range processes {
|
||||
fmt.Println("killing", ps.Process)
|
||||
group, _ := os.FindProcess(ps.Process.Pid)
|
||||
for name, ps := range processes {
|
||||
SystemOutput(fmt.Sprintf("sending SIGTERM to %s", name))
|
||||
group, _ := os.FindProcess(-1 * ps.Process.Pid)
|
||||
group.Signal(syscall.SIGTERM)
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Println("really killing")
|
||||
for _, ps := range processes {
|
||||
fmt.Println("killing", ps.Process)
|
||||
ps.Process.Signal(syscall.SIGKILL)
|
||||
b, _ := os.FindProcess(-1 * ps.Process.Pid)
|
||||
b.Signal(syscall.SIGKILL)
|
||||
time.Sleep(shutdownGraceTime)
|
||||
for name, ps := range processes {
|
||||
SystemOutput(fmt.Sprintf("sending SIGKILL to %s", name))
|
||||
group, _ := os.FindProcess(-1 * ps.Process.Pid)
|
||||
group.Signal(syscall.SIGKILL)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user