go gin web服务器使用fvbock/endless优雅地重启或停止
gin使用fvbock/endless
gin
正常使用注册路由时:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
使用 fvbock/endless
package main
import (
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
endless.ListenAndServe(":8000", r) // 注意这一行要使用endless
}
编译
$ go build -o endless test.go
$ ./endless
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /ping --> main.main.func1 (3 handlers)
2024/06/18 20:00:29 83605 :8000
[GIN] 2024/06/18 - 20:02:06 | 200 | 34.249µs | 127.0.0.1 | GET "/ping"
控制台也有相应的响应:[GIN] 2024/06/18 - 20:02:06 | 200 | 34.249µs | 127.0.0.1 | GET "/ping"
修改源码,重新编译
注意之前的服务不要动,重新开新的窗口
修改源码,重新编译
package main
import (
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong111", // 这行被修改了
})
})
endless.ListenAndServe(":8000", r) // 注意这一行要使用endless
}
此时新编译的包,会覆盖当前的旧包
go build -o endless test.go
查看进程
$ ps -ef | grep endless
501 83605 82947 0 8:00PM ttys004 0:00.02 ./endless
使用kill命令向老进程发送信号,这里是关键
kill -1 83605
这时第一个窗口就会有如下输出:
[GIN-debug] GET /ping --> main.main.func1 (3 handlers)
2024/06/18 20:09:16 84638 :8000
2024/06/18 20:09:16 83605 Received SIGTERM.
2024/06/18 20:09:16 83605 [::]:8000 Listener closed.
2024/06/18 20:09:16 83605 Waiting for connections to finish...
2024/06/18 20:09:16 83605 Serve() returning...
再次查看进程,发送请求
$ ps -ef | grep endless
501 84638 1 0 8:09PM ttys004 0:00.01 ./endless
endless
进程还在,可进程号变了,内容也变了
这里发生了变化,流程如下:
- 老的进程收到SIGHUP信号,拒绝新连接请求旧进程,但要保证已有连接正常
- 启动了一个新的子进程,端口号还是8000
- 新的子进程开始 Acce,系统将新的请求转交新的子进程,老进程不会处理新的连接了,但是会依然处理还没有处理完的老连接,直到所有老的连接都处理完
- 旧进程处理完所有旧连接后正常结束,新的进程会处理新的连接,整个服务正常运行
信号
信号是 Unix 、类 Unix 以及其他 POSIX 兼容的操作系统中进程间通讯的一种有限制的方式
它是一种异步的通知机制,用来提醒进程一个事件(硬件异常、程序执行异常、外部发出信号)已经发生。当一个信号发送给一个进程,操作系统中断了进程正常的控制流程。此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数。
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
endless server
监听以下几种信号量:
- syscall.SIGHUP:触发 fork 子进程和重新启动
- syscall.SIGUSR1/syscall.SIGTSTP:被监听,但不会触发任何动作
- syscall.SIGUSR2:触发 hammerTime
- syscall.SIGINT/syscall.SIGTERM:触发服务器关闭(会完成正在运行的请求)
endless
正正是依靠监听这些信号量,完成管控的一系列动作
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2020-06-18 Xshell连接VMware虚拟机中的CentOS
2020-06-18 Xshell连接VirtualBox虚拟机中的CentOS
2020-06-18 Centos安装完成后,ifconfig:command not found
2019-06-18 Yii2 TimestampBehavior 用来自动给指定的属性填充当前时间戳
2019-06-18 yii2时区语言设置
2019-06-18 yii2 gii开启
2019-06-18 yii components文件到底应该放些什么代码