美文网首页
让你的golang程序支持重启命令

让你的golang程序支持重启命令

作者: zhyuzh3d | 来源:发表于2023-05-01 10:18 被阅读0次

    能不能让Golang服务器程序运行后,输入r命令让程序一键自动重启?

    交互命令重启

    下面是个简单有效的办法(只是重新启动服务,不编译更新)

    // 监听命令
    func listenCmd() {
        f := "start.listenCmd"
        scanner := bufio.NewScanner(os.Stdin)
        for scanner.Scan() {
            switch scanner.Text() {
            case "r", "reset":
                restartZapp()
            case "q", "quit":
                os.Exit(0)
            }
        }
    }
    
    // 重启命令
    func restartZapp() {
        executablePath, _ := os.Executable()
        syscall.Exec(executablePath, os.Args, os.Environ())
    }
    

    然后在你的main函数里面第一行添加go listenCmd()然后就成功了!程序启动之后,只要输入r就能完整重启。

    root@iZuf612crf3p3310kvf8qgZ:~/zapp# go run zapp.go -port 80
    [2023-05-02 05:05:05][start.createServer]:Starting server on:80...
    r
    [2023-05-02 05:05:05][start.listenCmd]:Restarting...
    [2023-05-02 05:05:05][start.createServer]:Starting server on:80...
    

    如何捕获启动参数,比如上面的-port 80

    portPntr := flag.Int("port", conf.C.HttpPort, "Server listen on this port.")
    flag.Parse()
    Port= *portPntr
    

    但这个方法不是重新编译运行Golang服务,只是把已经运行的程序重新启动一遍。

    一键重新编译运行

    因为服务程序需要避免端口重复被占用,所以服务中就要包含终止之前服务的代码,因此,如果在代码中重新启动自身,就会先把自己杀死,导致根本不会启动。

    解决的办法是新建另外一个Golang程序launcher,用它来启动另外的myapp.go。代码如下。

    package main
    import (
        "bufio"
        "fmt"
        "os"
        "os/exec"
        "syscall"
    )
    
    func main() {
        fmt.Println("Launcher is ready...")
        scanner := bufio.NewScanner(os.Stdin)
        for scanner.Scan() {
            switch scanner.Text() {
            case "r", "reset":
                fmt.Println("Restarting...")
                os.Chdir("/root/zapp/")
                go run()
            case "q", "quit":
                fmt.Println("Quit...")
                os.Exit(0)
            }
        }
        select {}
    }
    func run() {
        cmd := exec.Command("go", "run", "myapp.go", "-port", "80")
        cmd.SysProcAttr = &syscall.SysProcAttr{
            Foreground: false,
        }
        err := cmd.Start()
        if err != nil {
            fmt.Println("New Zapp start failed:", err)
            return
        } else {
            fmt.Println("New Zapp run successed.")
        }
        err = cmd.Wait()
        if err != nil {
            fmt.Println("Old Zapp ended:", err)
            return
        }
    }
    

    这个程序启动后,输入r回车就会自动运行 "myapp.go"文件,实现实时更新。但这个方法的缺点是不能直接切入程序看到程序输出。

    最佳解决方案

    使用IDE的快捷键直接重启程序可能是最好的办法,下面以VSCode为例,分三步:

    1、从首选项打开快捷键设置,然后进入json配置文件编辑模式。


    image.png

    2、然后修改下面两个位置,其他不要动,text里可以\n就是多行命令,注意这里重复了两次go run命令,第一行是结束当前程序(见下一步),第二行才是启动新程序:

    image.png
    3、让你的程序支持交换命令退出,收到第一行go run之后就退出。方法是,添加下面函数,并在main中go listenCmd()首先运行它。
    func listenCmd() {
        f := "start.listenCmd"
        scanner := bufio.NewScanner(os.Stdin)
        for scanner.Scan() {
            text := scanner.Text()
            switch {
            case strings.HasPrefix(text, "go run") || text == "q" || text == "quit":
                logger.Info(f, "Quit...")
                os.Exit(0)
            }
        }
    }
    

    成功之后,使用快捷键Cmd+D就会执行两次go run...第一行被正在运行的Golang程序捕获,Golang程序退出,第二行才是重新运行。首次执行会浪费一次,其实Golang编译超快也无所谓。

    以上,就是实现一键重启Golang程序的可行性办法,有用的话请点赞收藏。

    相关文章

      网友评论

          本文标题:让你的golang程序支持重启命令

          本文链接:https://www.haomeiwen.com/subject/elsojdtx.html