如何让golang编译的iris框架网站程序类似nginx那样可

2020-07-28  本文已影响0人  Fesion

用golang开发的项目越来越多了,他们都跑在服务器上。但是他们都是在shell中运行的,如果关闭了终端,它就自动停止了。这显然不符合我们的需求,服务中断了还怎么服务用户啊。现在市面上流行的有几种解决方案,最简单的是使用nohup /data/wwwroot/build_app& 来实现将进程抛到后台去。也可以使用pm2来启动管理进程的。使用supervise的。也有使用daemon来实现的。下面我们就尝试使用daemon的方式来实现一个守护进程。

golang的daemon守护进程的代码实现

golang中启用daemon的方法很简单,已经有别人造好的轮子了,我们就不再造一遍,直接引用即可。使用的是syscall来处理进程。网上的实例使用的是http.Server服务,由于我使用的是iris框架,所以我重新实现了一个针对iris框架可用的daemon守护进程实现方式。它支持启动、关闭、重启等命令,模仿这nginx的命令操作来实现的。

核心代码

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "syscall"
    "video"

    "github.com/medivh-jay/daemon"
    "github.com/spf13/cobra"
)

// HTTPServer http 服务器示例
type HTTPServer struct {
    http *video.Bootstrap
    cmd  *cobra.Command
}

// PidSavePath pid保存路径
func (httpServer *HTTPServer) PidSavePath() string {
    return "./"
}

// Name pid文件名
func (httpServer *HTTPServer) Name() string {
    return "http"
}

// SetCommand 从 daemon 获得 cobra.Command 对象
func (httpServer *HTTPServer) SetCommand(cmd *cobra.Command) {
    // 在这里添加参数时他的参数不是对应服务的 start stop restart 命令的, 比如这个示例服务
    // 他对应的是示例服务命令, s所以这里添加的自定义 flag 应该在 start 之前传入
    cmd.PersistentFlags().StringP("test", "t", "yes", "")
    httpServer.cmd = cmd
}

// Start 启动web服务
func (httpServer *HTTPServer) Start() {
    fmt.Println(httpServer.cmd.Flags().GetString("test"))
    http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
        fmt.Println("hello world")
        _, _ = writer.Write([]byte("hello world"))
    })
    httpServer.http = video.New(8088, "debug")
    httpServer.http.Serve()
}

// Stop 关闭web服务
func (httpServer *HTTPServer) Stop() error {
    fmt.Println("准备关闭服务器")
    err := httpServer.http.Shutdown()
    fmt.Println("服务器已经关闭")
    return err
}

// Restart 重启web服务前关闭http服务
func (httpServer *HTTPServer) Restart() error {
    fmt.Println("服务器关闭中")
    err := httpServer.Stop()
    return err
}

func main() {
    // 自定义输出文件
    out, _ := os.OpenFile("./http.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
    err, _ := os.OpenFile("./http_err.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)

    // 初始化一个新的运行程序
    proc := daemon.NewProcess(new(HTTPServer)).SetPipeline(nil, out, err)
    proc.On(syscall.SIGTERM, func() {
        fmt.Println("a custom signal")
    })
    // 示例,多级命令服务
    // 不要共享一个 worker 对象指针
    daemon.GetCommand().AddWorker(proc).AddWorker(proc)
    // 示例,主服务
    daemon.Register(proc)

    // 运行
    if rs := daemon.Run(); rs != nil {
        log.Fatalln(rs)
    }
}

bootstrap里面是iris的逻辑

package video

import (
    "fmt"
    "github.com/kataras/iris/v12"
    "github.com/kataras/iris/v12/middleware/recover"
)

type Bootstrap struct {
    Application *iris.Application
    Port        int
    LoggerLevel string
}

func New(port int, loggerLevel string) *Bootstrap {
    var bootstrap Bootstrap
    bootstrap.Application = iris.New()
    bootstrap.Port = port
    bootstrap.LoggerLevel = loggerLevel

    return &bootstrap
}

func (bootstrap *Bootstrap) loadGlobalMiddleware() {
    bootstrap.Application.Use(recover.New())
}

func (bootstrap *Bootstrap) LoadRoutes() {
    Register(bootstrap.Application)
}

func (bootstrap *Bootstrap) Serve() {
    bootstrap.Application.Logger().SetLevel(bootstrap.LoggerLevel)
    bootstrap.loadGlobalMiddleware()
    bootstrap.LoadRoutes()

    bootstrap.Application.Run(
        iris.Addr(fmt.Sprintf(":%d", bootstrap.Port)),
        iris.WithoutServerError(iris.ErrServerClosed),
        iris.WithoutBodyConsumptionOnUnmarshal,
    )
}

func (bootstrap *Bootstrap) Shutdown() error {
    bootstrap.Shutdown()

    return nil
}

控制器代码

package video

import (
    "github.com/kataras/iris/v12"
    "os"
    "time"
)

func Index(ctx iris.Context) {
  ctx.WriteString("hello")
}

func ParseVideo(ctx iris.Context) {
    v, err := os.Open("vv.mp4")
    if err != nil {
        ctx.WriteString(err.Error())
        return
    }
    defer v.Close()
    ctx.ServeContent(v, "vv.mp4", time.Now(), true)
}

路由器代码

package video

import "github.com/kataras/iris/v12"

func Register(app *iris.Application) {
    app.Use(Cors)
    app.Use(ParseToken)

  app.Get("/", Index)
    app.Get("/play", ParseVideo)
}

中间件代码,用来处理cors

package video

import (
    "github.com/kataras/iris/v12"
)

func Cors(ctx iris.Context) {
    origin := ctx.GetHeader("Origin")
    if origin == "" {
        origin = ctx.GetHeader("Referer")
    }
    ctx.Header("Access-Control-Allow-Origin", origin)
    ctx.Header("Access-Control-Allow-Credentials", "true")
    ctx.Header("Access-Control-Expose-Headers", "Content-Disposition")
    if ctx.Request().Method == "OPTIONS" {
        ctx.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,PATCH,OPTIONS")
        ctx.Header("Access-Control-Allow-Headers", "Content-Type, Api, Accept, Authorization, Admin")
        ctx.StatusCode(204)
        return
    }
    ctx.Next()
}

func ParseToken(ctx iris.Context) {

    ctx.Next()
}
上一篇下一篇

猜你喜欢

热点阅读