diff --git a/README.md b/README.md index ac73056..d8ea8b7 100644 --- a/README.md +++ b/README.md @@ -48,11 +48,16 @@ 3. 编译 `go build` 4. 启动、访问方式同上 -### 启动可选参数 +### 命令 -* -p 端口, 指定端口, 默认5920 -* -e 指定运行环境, dev|test|prod, dev模式下可查看更多日志信息, 默认prod -* -h 查看帮助 +* gocron web + * -p 端口, 指定端口, 默认5920 + * -e 指定运行环境, dev|test|prod, dev模式下可查看更多日志信息, 默认prod + * -d 后台运行 + * -h 查看帮助 +* gocron serv + * -s stop|status stop:停止gocron status:查看运行状态 + ## 安全 * 使用`https`访问保证数据传输安全, 可在web服务器如nginx中配置https,通过反向代理,访问内部的gocron diff --git a/cmd/serv.go b/cmd/serv.go new file mode 100644 index 0000000..0a792c8 --- /dev/null +++ b/cmd/serv.go @@ -0,0 +1,67 @@ +package cmd + +import ( + "github.com/urfave/cli" + "fmt" + "github.com/ouqiang/gocron/modules/utils" + "github.com/ouqiang/gocron/modules/app" + "os" + "syscall" +) + +var CmdServ = cli.Command{ + Name: "serv", + Usage: "manage gocron, ./gocron serv -s stop|status", + Action: runServ, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "s", + Value:"", + Usage: "stop|status", + }, + }, +} + +func runServ(ctx *cli.Context) { + if utils.IsWindows() { + fmt.Println("not support on windows") + return + } + option := ctx.String("s") + if !utils.InStringSlice([]string{"stop", "status"}, option) { + fmt.Println("invalid option") + return + } + app.InitEnv() + pid := app.GetPid() + if pid <= 0 { + fmt.Println("not running") + return + } + process ,err := os.FindProcess(pid) + if err != nil { + fmt.Println("not running", err) + return + } + switch option { + case "stop": + stop(process) + case "status": + status(process) + } +} + +func stop(process *os.Process) { + fmt.Println("stopping gocron......") + err := process.Signal(syscall.SIGTERM) + if err != nil { + fmt.Println("failed to kill process", err) + } else { + fmt.Println("stopped") + } +} + + +func status(process *os.Process) { + fmt.Printf("running, pid-[%d]\n", process.Pid) +} \ No newline at end of file diff --git a/cmd/web.go b/cmd/web.go index 6ae180e..43cda38 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -28,7 +28,7 @@ const InitProcess = 1 var CmdWeb = cli.Command{ Name: "web", Usage: "run web server", - Action: run, + Action: runWeb, Flags: []cli.Flag{ cli.IntFlag{ Name: "port,p", @@ -47,13 +47,14 @@ var CmdWeb = cli.Command{ }, } -func run(ctx *cli.Context) { +func runWeb(ctx *cli.Context) { // 设置守护进程 becomeDaemon(ctx) // 设置运行环境 setEnvironment(ctx) // 初始化应用 app.InitEnv() + app.WritePid() // 初始化模块 DB、定时任务等 initModule() // 捕捉信号,配置热更新等 @@ -65,6 +66,7 @@ func run(ctx *cli.Context) { // 注册中间件. routers.RegisterMiddleware(m) port := parsePort(ctx) + fmt.Println("server start") m.Run(port) } @@ -195,8 +197,13 @@ func getWebLogWriter() io.Writer { // 应用退出 func shutdown() { - if !app.Installed { + defer func() { + app.RemovePid() + logger.Info("已退出") os.Exit(0) + }() + + if !app.Installed { return } logger.Info("应用准备退出") @@ -222,6 +229,4 @@ func shutdown() { time.Sleep(3 * time.Second) taskNumInRunning = service.TaskNum.Num() } - logger.Info("已退出") - os.Exit(0) } \ No newline at end of file diff --git a/gocron.go b/gocron.go index d3131ec..49a48f8 100644 --- a/gocron.go +++ b/gocron.go @@ -13,7 +13,7 @@ import ( "github.com/ouqiang/gocron/cmd" ) -const AppVersion = "0.2" +const AppVersion = "0.3" func main() { app := cli.NewApp() @@ -22,6 +22,7 @@ func main() { app.Version = AppVersion app.Commands = []cli.Command{ cmd.CmdWeb, + cmd.CmdServ, } app.Flags = append(app.Flags, []cli.Flag{}...) app.Run(os.Args) diff --git a/modules/app/app.go b/modules/app/app.go index 7ed189f..81539bf 100644 --- a/modules/app/app.go +++ b/modules/app/app.go @@ -7,6 +7,8 @@ import ( "runtime" "github.com/ouqiang/gocron/modules/utils" "gopkg.in/ini.v1" + "io/ioutil" + "strconv" ) var ( @@ -17,8 +19,10 @@ var ( AppConfig string // 应用配置文件 Installed bool // 应用是否安装过 Setting *ini.Section // 应用配置 + PidFile string ) + func InitEnv() { runtime.GOMAXPROCS(runtime.NumCPU()) logger.InitLogger() @@ -31,6 +35,7 @@ func InitEnv() { LogDir = AppDir + "/log" DataDir = AppDir + "/data" AppConfig = ConfDir + "/app.ini" + PidFile = LogDir + "/gocron.pid" checkDirExists(ConfDir, LogDir, DataDir) Installed = IsInstalled() } @@ -45,6 +50,33 @@ func IsInstalled() bool { return true } +func WritePid() { + pid := os.Getpid() + pidStr := strconv.Itoa(pid) + err := ioutil.WriteFile(PidFile, []byte(pidStr), 0644) + if err != nil { + logger.Fatalf("写入pid文件失败", err) + } +} + +func GetPid() int { + bytes, err := ioutil.ReadFile(PidFile) + if err != nil { + return 0 + } + pidStr := string(bytes) + pid, err := strconv.Atoi(pidStr) + if err != nil { + return 0 + } + + return pid +} + +func RemovePid() { + os.Remove(PidFile) +} + // 创建安装锁文件 func CreateInstallLock() error { _, err := os.Create(ConfDir + "/install.lock")