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())
}
go listenCmd()
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配置文件编辑模式。


go run

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)
        }
    }
}
go run...

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