能不能让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
命令,第一行是结束当前程序(见下一步),第二行才是启动新程序:
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程序的可行性办法,有用的话请点赞收藏。
网友评论