2017-03-10 09:24:06 +00:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
2017-04-07 01:22:00 +00:00
|
|
|
"github.com/ouqiang/gocron/modules/app"
|
|
|
|
"github.com/ouqiang/gocron/routers"
|
2017-04-02 02:38:49 +00:00
|
|
|
"github.com/urfave/cli"
|
|
|
|
"gopkg.in/macaron.v1"
|
2017-04-04 06:42:33 +00:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"syscall"
|
2017-04-07 01:22:00 +00:00
|
|
|
"github.com/ouqiang/gocron/modules/logger"
|
2017-05-01 05:59:52 +00:00
|
|
|
"github.com/ouqiang/gocron/service"
|
|
|
|
"github.com/ouqiang/gocron/models"
|
2017-05-04 06:02:50 +00:00
|
|
|
"github.com/ouqiang/gocron/modules/setting"
|
2017-05-04 10:05:25 +00:00
|
|
|
"time"
|
2017-05-20 06:13:16 +00:00
|
|
|
"io"
|
|
|
|
"fmt"
|
2017-05-20 06:37:40 +00:00
|
|
|
"path/filepath"
|
|
|
|
"os/exec"
|
|
|
|
"github.com/ouqiang/gocron/modules/utils"
|
2017-03-10 09:24:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// web服务器默认端口
|
|
|
|
const DefaultPort = 5920
|
2017-04-02 02:19:52 +00:00
|
|
|
|
2017-05-20 06:37:40 +00:00
|
|
|
const InitProcess = 1
|
|
|
|
|
2017-03-10 09:24:06 +00:00
|
|
|
var CmdWeb = cli.Command{
|
2017-04-25 11:05:24 +00:00
|
|
|
Name: "web",
|
|
|
|
Usage: "run web server",
|
2017-04-02 02:38:49 +00:00
|
|
|
Action: run,
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.IntFlag{
|
|
|
|
Name: "port,p",
|
|
|
|
Value: DefaultPort,
|
2017-05-20 06:37:40 +00:00
|
|
|
Usage: "bind port",
|
2017-04-02 02:38:49 +00:00
|
|
|
},
|
2017-04-03 07:27:19 +00:00
|
|
|
cli.StringFlag{
|
|
|
|
Name: "env,e",
|
2017-04-23 09:00:47 +00:00
|
|
|
Value: "prod",
|
2017-04-03 07:27:19 +00:00
|
|
|
Usage: "runtime environment, dev|test|prod",
|
|
|
|
},
|
2017-05-20 06:37:40 +00:00
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "d",
|
|
|
|
Usage: "-d=true, run as daemon process",
|
|
|
|
},
|
2017-04-02 02:38:49 +00:00
|
|
|
},
|
2017-03-10 09:24:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func run(ctx *cli.Context) {
|
2017-05-20 06:37:40 +00:00
|
|
|
// 设置守护进程
|
|
|
|
becomeDaemon(ctx)
|
2017-04-04 06:42:33 +00:00
|
|
|
// 设置运行环境
|
2017-04-03 07:27:19 +00:00
|
|
|
setEnvironment(ctx)
|
2017-04-04 06:42:33 +00:00
|
|
|
// 初始化应用
|
2017-04-02 02:38:49 +00:00
|
|
|
app.InitEnv()
|
2017-05-01 05:59:52 +00:00
|
|
|
// 初始化模块 DB、定时任务等
|
|
|
|
initModule()
|
2017-04-04 06:42:33 +00:00
|
|
|
// 捕捉信号,配置热更新等
|
|
|
|
go catchSignal()
|
2017-05-20 06:13:16 +00:00
|
|
|
m := macaron.NewWithLogger(getWebLogWriter())
|
2017-05-04 10:05:25 +00:00
|
|
|
|
2017-04-02 02:38:49 +00:00
|
|
|
// 注册路由
|
|
|
|
routers.Register(m)
|
2017-04-10 09:37:16 +00:00
|
|
|
// 注册中间件.
|
2017-04-13 09:35:59 +00:00
|
|
|
routers.RegisterMiddleware(m)
|
2017-04-02 02:38:49 +00:00
|
|
|
port := parsePort(ctx)
|
|
|
|
m.Run(port)
|
2017-03-10 09:24:06 +00:00
|
|
|
}
|
|
|
|
|
2017-05-20 06:37:40 +00:00
|
|
|
func becomeDaemon(ctx *cli.Context) {
|
|
|
|
// 不支持windows
|
|
|
|
if utils.IsWindows() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !ctx.IsSet("d") {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if os.Getppid() == InitProcess {
|
|
|
|
// 子进程不再处理
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
filePath, _:= filepath.Abs(os.Args[0])
|
|
|
|
cmd := exec.Command(filePath, os.Args[1:]...)
|
|
|
|
cmd.Stdin = os.Stdin
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
cmd.Start()
|
|
|
|
|
|
|
|
// 父进程退出, 子进程由init-1号进程收养
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2017-05-01 05:59:52 +00:00
|
|
|
func initModule() {
|
2017-05-01 06:12:21 +00:00
|
|
|
if !app.Installed {
|
|
|
|
return
|
|
|
|
}
|
2017-05-04 06:02:50 +00:00
|
|
|
|
|
|
|
config, err := setting.Read(app.AppConfig)
|
|
|
|
if err != nil {
|
|
|
|
logger.Fatal("读取应用配置失败", err)
|
|
|
|
}
|
|
|
|
app.Setting = config
|
|
|
|
|
2017-05-01 05:59:52 +00:00
|
|
|
models.Db = models.CreateDb()
|
|
|
|
|
|
|
|
// 初始化定时任务
|
|
|
|
serviceTask := new(service.Task)
|
|
|
|
serviceTask.Initialize()
|
2017-05-14 14:09:36 +00:00
|
|
|
|
2017-05-16 03:03:28 +00:00
|
|
|
// 初始化延时任务
|
2017-05-14 14:09:36 +00:00
|
|
|
delayTaskEnabled, err := config.Key("delay.task.enable").Bool()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !delayTaskEnabled {
|
|
|
|
return
|
|
|
|
}
|
2017-05-16 03:03:28 +00:00
|
|
|
delayTaskSlots, err := config.Key("delay.task.slots").Int()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
delayTaskTick := config.Key("delay.task.tick").String()
|
|
|
|
tick, err := time.ParseDuration(delayTaskTick)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-05-14 14:09:36 +00:00
|
|
|
serviceDelayTask := new(service.DelayTask)
|
2017-05-16 03:03:28 +00:00
|
|
|
serviceDelayTask.Initialize(tick, delayTaskSlots)
|
2017-05-01 05:59:52 +00:00
|
|
|
}
|
|
|
|
|
2017-03-10 09:24:06 +00:00
|
|
|
// 解析端口
|
|
|
|
func parsePort(ctx *cli.Context) int {
|
2017-04-03 07:27:19 +00:00
|
|
|
var port int = DefaultPort
|
2017-04-02 02:38:49 +00:00
|
|
|
if ctx.IsSet("port") {
|
|
|
|
port = ctx.Int("port")
|
|
|
|
}
|
|
|
|
if port <= 0 || port >= 65535 {
|
|
|
|
port = DefaultPort
|
|
|
|
}
|
2017-03-10 09:24:06 +00:00
|
|
|
|
2017-04-02 02:38:49 +00:00
|
|
|
return port
|
2017-04-02 02:19:52 +00:00
|
|
|
}
|
2017-04-03 07:27:19 +00:00
|
|
|
|
|
|
|
func setEnvironment(ctx *cli.Context) {
|
2017-04-23 09:00:47 +00:00
|
|
|
var env string = "prod"
|
2017-04-03 07:27:19 +00:00
|
|
|
if ctx.IsSet("env") {
|
|
|
|
env = ctx.String("env")
|
|
|
|
}
|
|
|
|
|
2017-04-23 09:00:47 +00:00
|
|
|
switch env {
|
|
|
|
case "test":
|
|
|
|
macaron.Env = macaron.TEST
|
|
|
|
case "dev":
|
|
|
|
macaron.Env = macaron.DEV
|
2017-05-12 01:59:22 +00:00
|
|
|
default:
|
|
|
|
macaron.Env = macaron.PROD
|
2017-04-03 07:27:19 +00:00
|
|
|
}
|
2017-04-04 06:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 捕捉信号
|
|
|
|
func catchSignal() {
|
|
|
|
c := make(chan os.Signal)
|
2017-04-06 06:40:48 +00:00
|
|
|
// todo 配置热更新, windows 不支持 syscall.SIGUSR1, syscall.SIGUSR2
|
|
|
|
signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
|
2017-04-04 09:05:55 +00:00
|
|
|
for {
|
|
|
|
s := <- c
|
|
|
|
logger.Info("收到信号 -- ", s)
|
|
|
|
switch s {
|
2017-05-05 05:44:44 +00:00
|
|
|
case syscall.SIGHUP:
|
|
|
|
logger.Info("收到终端断开信号, 忽略")
|
|
|
|
case syscall.SIGINT, syscall.SIGTERM:
|
2017-05-04 10:05:25 +00:00
|
|
|
shutdown()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-20 06:13:16 +00:00
|
|
|
func getWebLogWriter() io.Writer {
|
|
|
|
if macaron.Env == macaron.DEV {
|
|
|
|
return os.Stdout
|
|
|
|
}
|
|
|
|
logFile := app.LogDir + "/access.log"
|
|
|
|
var err error
|
|
|
|
w, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND ,0666)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("日志文件[%s]打开失败", logFile)
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return w
|
|
|
|
}
|
|
|
|
|
|
|
|
// 应用退出
|
2017-05-04 10:05:25 +00:00
|
|
|
func shutdown() {
|
2017-05-06 04:48:17 +00:00
|
|
|
if !app.Installed {
|
|
|
|
os.Exit(0)
|
|
|
|
return
|
|
|
|
}
|
2017-05-16 03:03:28 +00:00
|
|
|
logger.Info("应用准备退出")
|
2017-05-04 10:05:25 +00:00
|
|
|
serviceTask := new(service.Task)
|
|
|
|
// 停止所有任务调度
|
2017-05-16 03:03:28 +00:00
|
|
|
logger.Info("停止定时任务调度")
|
2017-05-04 10:05:25 +00:00
|
|
|
serviceTask.StopAll()
|
2017-05-14 14:09:36 +00:00
|
|
|
delayTaskEnable, _ := app.Setting.Key("delay.task.enable").Bool()
|
|
|
|
if delayTaskEnable {
|
2017-05-16 03:03:28 +00:00
|
|
|
logger.Info("停止延时任务调度")
|
2017-05-14 14:09:36 +00:00
|
|
|
serviceDelayTask := new(service.DelayTask)
|
|
|
|
serviceDelayTask.Stop()
|
|
|
|
}
|
2017-05-04 10:05:25 +00:00
|
|
|
taskNumInRunning := service.TaskNum.Num()
|
2017-05-08 06:07:06 +00:00
|
|
|
logger.Infof("正在运行的任务有%d个", taskNumInRunning)
|
|
|
|
if taskNumInRunning > 0 {
|
|
|
|
logger.Info("等待所有任务执行完成后退出")
|
|
|
|
}
|
2017-05-04 10:05:25 +00:00
|
|
|
for {
|
|
|
|
if taskNumInRunning <= 0 {
|
|
|
|
break
|
2017-04-04 09:05:55 +00:00
|
|
|
}
|
2017-05-04 10:05:25 +00:00
|
|
|
time.Sleep(3 * time.Second)
|
|
|
|
taskNumInRunning = service.TaskNum.Num()
|
2017-04-04 09:05:55 +00:00
|
|
|
}
|
2017-05-04 10:05:25 +00:00
|
|
|
logger.Info("已退出")
|
|
|
|
os.Exit(0)
|
2017-04-03 07:27:19 +00:00
|
|
|
}
|