Foreword
After each finished updating the code, finished updating the configuration file directly so ctrl+c
really no question, ctrl+c
in the end done things?
In this section we briefly about the ctrl+c
signal behind and how to Gin
gracefully restart the service, which is to HTTP
serve hot update
Project Address: https://github.com/EDDYCJY/go-gin-example
ctrl + c
Kernel sends a signal, in some cases, such as when a process to produce a pipeline has been closed write data
SIGPIPE
signal
The terminal performs a specific key combination allows the system to transmit a specific signal to the process, to complete the series of operations
command | signal | meaning |
---|---|---|
ctrl + c | SIGINT | End of compulsory process |
ctrl + z | SIGTSTP | The task is interrupted, the process hangs |
ctrl + \ | SIGQUIT | End of the process and dump core |
ctrl + d | EOF | |
Sigःuf | Terminate the process receive the signal. If the program does not capture the signal, when the signal is received, the process will exit (commonly used to restart, reload process) |
So we execute ctrl + c
shut down gin
when the server will force the end of the process, causing the user is visiting and other problems
Common kill -9 pid
will send SIGKILL
a signal to the process, but also a similar result
signal
What this paragraph repeated signal is it?
Signal Unix
, the class Unix
and the other POSIX
one kind of inter-compatible operating system in the process of communication has restricted manner
It is an asynchronous notification mechanism to alert the process of an event (hardware abnormality, abnormal program execution, external signals) has occurred. When a signal is sent to a process, the process of the operating system interrupts the normal flow of control. At this time, any non-atomic operation will be interrupted. If the process is defined signal processing functions, then it will be executed, otherwise execute the default handler
All signals
$ 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
How elegant count
purpose
- Without closing existing connection (program is running)
- The new process is started and replace the old process
- The new process takes over a new connection
- To connect at any time in response to user requests, when a user requests still remain connected to the old process, the new user should request a new process, rejecting the request not appear in the case
Process
1, replace or modify executable profile
2, the amount of the transmission signal SIGHUP
3, reject new connection requests the old process, but to ensure the normal existing connection
4, start a new child process
5, new child process begins Accet
6, the system will transmit a new request for a new child process
7, the old process processed normally ended after all the old connection
A graceful restart
endless
Zero downtime restarts for golang HTTP and HTTPS servers. (for golang 1.3+)
We use fvbock / endless to achieve Golang HTTP/HTTPS
service restarts zero downtime
endless server
Semaphore monitor the following:
- syscall.SIGHUP: Trigger
fork
child process and restart - syscall.SIGUSR1 / syscall.SIGTSTP: to be listening, but will not trigger any action
- syscall.SIGUSR2: Trigger
hammerTime
- syscall.SIGINT / syscall.SIGTERM: trigger server closes (completes running requests)
endless
It was on these positive signals amount of monitoring, management and control of the complete series of actions
installation
go get -u github.com/fvbock/endless
write
Open the gin-blog the main.go
file, modify the file:
package main
import (
"fmt"
"log"
"syscall"
"github.com/fvbock/endless"
"gin-blog/routers"
"gin-blog/pkg/setting"
)
func main() {
endless.DefaultReadTimeOut = setting.ReadTimeout
endless.DefaultWriteTimeOut = setting.WriteTimeout
endless.DefaultMaxHeaderBytes = 1 << 20
endPoint := fmt.Sprintf(":%d", setting.HTTPPort)
server := endless.NewServer(endPoint, routers.InitRouter())
server.BeforeBegin = func(add string) {
log.Printf("Actual pid is %d", syscall.Getpid())
}
err := server.ListenAndServe()
if err != nil {
log.Printf("Server err: %v", err)
}
}
endless.NewServer
Returns an initialized endlessServer
object, BeforeBegin
the output of the current process pid
, call ListenAndServe
the actual "start" service
verification
Compile
$ go build main.go
carried out
$ ./main
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
...
Actual pid is 48601
After a successful start, the output pid
is 48601; in another terminal execution kill -1 48601
, inspection prior service terminal effect
[root@localhost go-gin-example]# ./main
[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 /auth --> ...
[GIN-debug] GET /api/v1/tags --> ...
...
Actual pid is 48601
...
Actual pid is 48755
48601 Received SIGTERM.
48601 [::]:8000 Listener closed.
48601 Waiting for connections to finish...
48601 Serve() returning...
Server err: accept tcp [::]:8000: use of closed network connection
We can see that the command has been suspended, and fork
a new child process pid
is 48755
48601 Received SIGTERM.
48601 [::]:8000 Listener closed.
48601 Waiting for connections to finish...
48601 Serve() returning...
Server err: accept tcp [::]:8000: use of closed network connection
Roughly meaning the main process ( pid
to 48601) received SIGTERM
semaphore, turn off the main process of listening and waiting for the completion of the request being executed; this is consistent with our previously described
wake
At this time in postman
the access our interface again, you can pleasantly surprised to find him "Resurrection"!
Actual pid is 48755
48601 Received SIGTERM.
48601 [::]:8000 Listener closed.
48601 Waiting for connections to finish...
48601 Serve() returning...
Server err: accept tcp [::]:8000: use of closed network connection
$ [GIN] 2018/03/15 - 13:00:16 | 200 | 188.096µs | 192.168.111.1 | GET /api/v1/tags...
This completes a positive flow of
Think about it, every update release, or modify the configuration files, just give the process sends SIGTERM signal, without the need to force the end of the application, how convenient and safe thing!
problem
endless
Hot update is to take ran after a fork, the original process out of the way, this does not meet the requirements of the daemon
http.Server - Shutdown()
If you are Golang >= 1.8
, you can also consider using http.Server
the Shutdown method
package main
import (
"fmt"
"net/http"
"context"
"log"
"os"
"os/signal"
"time"
"gin-blog/routers"
"gin-blog/pkg/setting"
)
func main() {
router := routers.InitRouter()
s := &http.Server{
Addr: fmt.Sprintf(":%d", setting.HTTPPort),
Handler: router,
ReadTimeout: setting.ReadTimeout,
WriteTimeout: setting.WriteTimeout,
MaxHeaderBytes: 1 << 20,
}
go func() {
if err := s.ListenAndServe(); err != nil {
log.Printf("Listen: %s\n", err)
}
}()
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)
<- quit
log.Println("Shutdown Server ...")
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
defer cancel()
if err := s.Shutdown(ctx); err != nil {
log.Fatal("Server Shutdown:", err)
}
log.Println("Server exiting")
}
summary
In the daily service, elegant restart (hot update) is a very important part. And Golang
in HTTP
the heat update service, there are many aspects of the program, we should choose the most appropriate depending on the application scenario