func (p *Process) startCommand() { // p.Stdout.Reset() // p.Stderr.Reset() // p.Output.Reset() // Donot reset because log is still needed. log.Printf("start cmd(%s): %s", p.Name, p.Command) p.cmd = p.buildCommand() p.SetState(Running) if err := p.cmd.Start(); err != nil { log.Warnf("program %s start failed: %v", p.Name, err) p.SetState(Fatal) return } go func() { errC := GoFunc(p.cmd.Wait) startTime := time.Now() select { case <-errC: // if p.cmd.Wait() returns, it means program and its sub process all quited. no need to kill again // func Wait() will only return when program session finishs. (Only Tested on mac) log.Printf("program(%s) finished, time used %v", p.Name, 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.Printf("program(%s) exit too quick, status -> fatal", p.Name) return } } p.waitNextRetry() case <-p.stopC: log.Println("recv stop command") p.stopCommand() // clean up all process } }() }
func configReader(fileName string) error { stat, err := os.Stat(fileName) if err != nil { log.Printf("Failed to find config file: %s\n", err) return err } if !stat.ModTime().After(lastReadConfig) { return err } lastReadConfig = time.Now() log.Printf("Loading config: %s\n", fileName) cfg := new(AppConfig) err = gcfg.ReadFileInto(cfg, fileName) if err != nil { log.Printf("Failed to parse config data: %s\n", err) return err } //cfg.Flags.HasStatHat = len(cfg.StatHat.ApiKey) > 0 // log.Println("STATHAT APIKEY:", cfg.StatHat.ApiKey) // log.Println("STATHAT FLAG :", cfg.Flags.HasStatHat) Config = cfg go startWorker() return nil }
func (p *Process) stopCommand() { p.mu.Lock() defer p.mu.Unlock() defer p.SetState(Stopped) if p.cmd == nil { return } p.SetState(Stopping) if p.cmd.Process != nil { p.cmd.Process.Signal(syscall.SIGTERM) // TODO(ssx): add it to config } select { case <-GoFunc(p.cmd.Wait): log.Printf("program(%s) quit normally", p.Name) case <-time.After(time.Duration(p.StopTimeout) * time.Second): // TODO: add 3s to config log.Printf("program(%s) terminate all", p.Name) p.cmd.Terminate(syscall.SIGKILL) // cleanup } err := p.cmd.Wait() // This is OK, because Signal KILL will definitely work prefixStr := "\n--- GOSUV LOG " + time.Now().Format("2006-01-02 15:04:05") if err == nil { io.WriteString(p.cmd.Stderr, fmt.Sprintf("%s exit success ---\n\n", prefixStr)) } else { io.WriteString(p.cmd.Stderr, fmt.Sprintf("%s exit %v ---\n\n", prefixStr, err)) } if p.OutputFile != nil { p.OutputFile.Close() p.OutputFile = nil } p.cmd = nil }
func main() { configfn := flag.String("config", "default.conf", "location of configuration file") flag.Parse() data, err := ioutil.ReadFile(*configfn) if err != nil { log.Fatalf("server: cannot load configuration file[%s] (%v)", *configfn, err) } var conf config.Server if _, err := toml.Decode(string(data), &conf); err != nil { log.Fatalf("server: configuration file[%s] is not valid (%v)", *configfn, err) } // default is that cfs is bootstrapped using docker cname, err := detectDockerContainer() if err != nil { log.Printf("server: failed to detect docker container (%v)", err) } else { stats.SetContainerName(cname) log.Printf("server: detect docker container %q", cname) } log.Infof("server: starting server...") lis, err := net.Listen("tcp", net.JoinHostPort(conf.Bind, conf.Port)) if err != nil { log.Fatalf("server: failed to listen: %v", err) } log.Infof("server: listening on %s", net.JoinHostPort(conf.Bind, conf.Port)) cfs := NewServer() for _, d := range conf.Disks { err = cfs.AddDisk(d.Name, d.Root) if err != nil { log.Fatalf("server: failed to add disk (%v)", err) } } // 0x1234 is the client ID for cfsctl, and its quota is 10 req/sec. enforce.SetQuota(0x1234, 10) // TODO report with influxSinker stats.Report(nil, 3*time.Second) s := grpc.NewServer() pb.RegisterCfsServer(s, cfs) pb.RegisterStatsServer(s, stats.Server()) log.Infof("server: ready to serve clients") s.Serve(lis) }
func handleStats(ctx context.Context, c *client.Client) error { info, err := c.ContainerInfo(ctx) if err != nil { log.Printf("ContainerInfo err (%v)", err) } else { log.Printf("Container Info: %+v", info) } ms, err := c.Metrics(ctx) if err != nil { log.Printf("Metrics err (%v)", err) } else { log.Printf("Metrics: %+v", ms) } return nil }
func (k *Keeper) ListUniqRecords() (rs []*Record, err error) { traveled := make(map[string]bool) rs = make([]*Record, 0) for _, rec := range k.runRecs { traveled[rec.Name] = true rs = append(rs, rec) } for _, task := range k.orderedTasks() { if traveled[task.Name] { continue } traveled[task.Name] = true var rec = new(Record) exists, err := xe.Where("`name` = ?", task.Name).Desc("created_at").Get(rec) if !exists || err != nil { log.Printf("exists: %v, err: %v", exists, err) rec.Name = task.Name rec.Status = STATUS_PENDING rec.T = task } rs = append(rs, rec) } return rs, nil }
func (p *ProxyConn) pipe(src, dst net.Conn) chan error { //data direction errch := make(chan error, 1) islocal := src == p.lconn //directional copy (64k buffer) buff := make([]byte, 0xffff) go func() { for { n, err := src.Read(buff) if err != nil { errch <- err return } b := buff[:n] //write out result n, err = dst.Write(b) if err != nil { errch <- err log.Printf("Write failed '%s'\n", err) return } log.Debug("pipe --> local:", islocal, "write:", n) //, string(b[:n])) if islocal { p.sentBytes += uint64(n) p.stats.sentBytes += uint64(n) } else { p.receivedBytes += uint64(n) p.stats.receivedBytes += uint64(n) } } }() return errch }
func (s *Supervisor) wsEvents(w http.ResponseWriter, r *http.Request) { c, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Print("upgrade:", err) return } defer c.Close() ch := make(chan string, 0) s.addStatusChangeListener(ch) go func() { _, _ = <-ch // ignore the history messages for message := range ch { // Question: type 1 ? c.WriteMessage(1, []byte(message)) } // s.eventB.RemoveListener(ch) }() for { mt, message, err := c.ReadMessage() if err != nil { log.Println("read:", mt, err) break } log.Printf("recv: %v %s", mt, message) err = c.WriteMessage(mt, message) if err != nil { log.Println("write:", err) break } } }
func main() { flag.Parse() log.SetOutputLevel(*flagdebug) configFileName := filepath.Clean(*flagconfig + "/main.conf") log.Debugf("config file '%s'\n", configFileName) log.Printf("Starting %s\n", VERSION) if *cpuprofile != "" { prof, err := os.Create(*cpuprofile) if err != nil { panic(err.Error()) } pprof.StartCPUProfile(prof) defer func() { log.Println("closing file") prof.Close() }() defer func() { log.Println("stopping profile") pprof.StopCPUProfile() }() } go configWatcher(configFileName) terminate := make(chan os.Signal) signal.Notify(terminate, os.Interrupt) <-terminate log.Printf("signal received, stopping") if *memprofile != "" { f, err := os.Create(*memprofile) if err != nil { log.Fatal(err) } pprof.WriteHeapProfile(f) f.Close() } //os.Exit(0) }
func (s *Supervisor) AutoStartPrograms() { for _, proc := range s.procMap { if proc.Program.StartAuto { log.Printf("auto start %s", strconv.Quote(proc.Name)) proc.Operate(StartEvent) } } }
func (s *Supervisor) removeProgram(name string) { names := make([]string, 0, len(s.names)) for _, pName := range s.names { if pName == name { continue } names = append(names, pName) } s.names = names log.Printf("stop before delete program: %s", name) s.stopAndWait(name) delete(s.procMap, name) delete(s.pgMap, name) s.broadcastEvent(name + " deleted") }
func (s *Supervisor) catchExitSignal() { sigC := make(chan os.Signal, 1) signal.Notify(sigC, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) go func() { for sig := range sigC { if sig == syscall.SIGHUP { log.Println("Receive SIGHUP, just ignore") continue } log.Printf("Got signal: %v, stopping all running process\n", sig) s.Close() break } os.Exit(0) }() }
func actionStartServer(c *cli.Context) error { suv, hdlr, err := newSupervisorHandler() if err != nil { log.Fatal(err) } auth := cfg.Server.HttpAuth if auth.Enabled { hdlr = httpauth.SimpleBasicAuth(auth.User, auth.Password)(hdlr) } http.Handle("/", hdlr) addr := cfg.Server.Addr if c.Bool("foreground") { suv.AutoStartPrograms() log.Printf("server listen on %v", addr) log.Fatal(http.ListenAndServe(addr, nil)) } else { if checkServerStatus() == nil { fmt.Println("server is already running") return nil } logPath := filepath.Join(defaultConfigDir, "gosuv.log") logFd, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { log.Fatalf("create file %s failed: %v", logPath, err) } cmd := exec.Command(os.Args[0], "start-server", "-f") cmd.Stdout = logFd cmd.Stderr = logFd err = cmd.Start() if err != nil { log.Fatal(err) } select { case err = <-GoFunc(cmd.Wait): log.Fatalf("server started failed, %v", err) case <-time.After(200 * time.Millisecond): showAddr := addr if strings.HasPrefix(addr, ":") { showAddr = "0.0.0.0" + addr } fmt.Printf("server started, listening on %s\n", showAddr) } } return nil }
func addHandler(w http.ResponseWriter, r *http.Request) { pinfo := new(ProgramInfo) err := json.NewDecoder(r.Body).Decode(pinfo) if err != nil { http.Error(w, err.Error(), 502) return } log.Printf("add: %#v", pinfo) program := NewProgram(pinfo) if err = programTable.AddProgram(program); err != nil { http.Error(w, err.Error(), 503) return } program.InputData(EVENT_START) renderJSON(w, &JSONResponse{ Code: 200, Message: "program add success", }) }
func main() { flag.StringVar(&gcfg.SchedFile, "sched", "sched.json", "file which store schedule setting") flag.IntVar(&gcfg.ServerPort, "port", 4000, "port to listen") flag.StringVar(&gcfg.LogDir, "logdir", "logs", "log directory") flag.Parse() var err error xe, err = xorm.NewEngine("sqlite3", "./test.db") //xe, err = xorm.NewEngine("mysql", "cron:cron@tcp(10.246.13.180:3306)/cron?charset=utf8") // xe, err = xorm.NewEngine("mysql", "root:@/cron?charset=utf8") if err != nil { log.Fatal(err) } if err := xe.Sync(Record{}); err != nil { log.Fatal(err) } if _, err = os.Stat(gcfg.LogDir); err != nil { os.Mkdir(gcfg.LogDir, 0755) } if _, err = os.Stat(gcfg.SchedFile); err != nil { ioutil.WriteFile(gcfg.SchedFile, []byte("[]"), 0644) } tasks, err := loadTasks(gcfg.SchedFile) if err != nil { log.Fatal(err) } log.Println(tasks) keeper = NewKeeper(tasks) initRoutes() log.Printf("Listening on *:%d", gcfg.ServerPort) http.Handle("/", m) //http.Handle("/-/", http.StripPrefix("/-/", http.FileServer(http.Dir("public")))) if err := http.ListenAndServe(":"+strconv.Itoa(gcfg.ServerPort), nil); err != nil { log.Fatal(err) } }
func parseCfgFile(file string, m *macaron.Macaron) error { fd, err := os.Open(file) if err != nil { return err } defer fd.Close() rd := bufio.NewReader(fd) for { bline, _, err := rd.ReadLine() // Just ignore isPrefix(maybe not good) if err != nil { break } line := string(bline) if strings.HasPrefix(line, "#") { continue } fields, err := shellquote.Split(line) if err != nil { log.Printf("Shellquote parse error: %v", err) continue } if !(len(fields) >= 3 && len(fields) <= 4) { continue } method, patten, script := fields[0], fields[1], fields[2] contentType := "" if len(fields) == 4 { contentType = fields[3] } else { } addRoute(m, method, patten, script, contentType) } return nil }