Go 应用程序关闭时的通道和信号使用
下面的示例处理文档中描述的正常服务器关闭。在阅读了其他文章和示例后,基于我的研发工作,我提出了这项工作,它实际上优雅地关闭了服务器。然而,由于我在Golang的经验/知识非常有限,我无法证明我是否正确使用了通道和信号。我只是想避免Goroutine泄密和其他看不见的潜在问题。有人能告诉我这件作品是否是惯用的围棋代码以及通道和信号的用法吗 内部/server/server.goGo 应用程序关闭时的通道和信号使用,go,signals,channel,Go,Signals,Channel,下面的示例处理文档中描述的正常服务器关闭。在阅读了其他文章和示例后,基于我的研发工作,我提出了这项工作,它实际上优雅地关闭了服务器。然而,由于我在Golang的经验/知识非常有限,我无法证明我是否正确使用了通道和信号。我只是想避免Goroutine泄密和其他看不见的潜在问题。有人能告诉我这件作品是否是惯用的围棋代码以及通道和信号的用法吗 内部/server/server.go package server import ( "net/http" ) type Server struc
package server
import (
"net/http"
)
type Server struct {
*http.Server
}
func NewServer() Server {
return Server{
&http.Server{Addr: ":8080", Handler: nil},
}
}
func (s Server) Start() error {
if err := s.ListenAndServe(); err != http.ErrServerClosed {
return err
}
return nil
}
package main
import (
"api/internal/app"
"api/internal/server"
"context"
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
// Some other bootstrapping and configuration code here ...
// ....
fmt.Printf("app starting")
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
ctx, cancel := context.WithCancel(context.Background())
go listenSignals(cancel, sigChan)
if err := app.New(server.NewServer()).Start(ctx); err != nil {
panic(err)
}
fmt.Print("app shutdown completed")
}
func listenSignals(cancel context.CancelFunc, sigChan chan os.Signal) {
sig := <-sigChan
fmt.Printf("app shutdown started with %v signal", sig)
cancel()
}
package app
import (
"api/internal/server"
"context"
"errors"
"fmt"
"time"
)
type App struct {
srv server.Server
}
func New(srv server.Server) App {
return App{srv: srv}
}
func (app App) Start(ctx context.Context) error {
doneChan := make(chan struct{})
go shutdown(ctx, doneChan, app)
// Start HTTP server
if err := a.srv.Start(); err != nil {
return errors.New("failed to start HTTP server")
}
// Start DB server
// ...
<-doneChan
return nil
}
func shutdown(ctx context.Context, doneChan chan<- struct{}, app App) {
<-ctx.Done()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Shutdown HTTP server
err := app.srv.Shutdown(ctx)
if err != nil {
fmt.Print("some active HTTP connections are interrupted at shutdown")
} else {
fmt.Print("no HTTP connections are interrupted at shutdown")
}
// Shutdown DB server
// ...
close(doneChan)
}
cmd/api/main.go
package server
import (
"net/http"
)
type Server struct {
*http.Server
}
func NewServer() Server {
return Server{
&http.Server{Addr: ":8080", Handler: nil},
}
}
func (s Server) Start() error {
if err := s.ListenAndServe(); err != http.ErrServerClosed {
return err
}
return nil
}
package main
import (
"api/internal/app"
"api/internal/server"
"context"
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
// Some other bootstrapping and configuration code here ...
// ....
fmt.Printf("app starting")
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
ctx, cancel := context.WithCancel(context.Background())
go listenSignals(cancel, sigChan)
if err := app.New(server.NewServer()).Start(ctx); err != nil {
panic(err)
}
fmt.Print("app shutdown completed")
}
func listenSignals(cancel context.CancelFunc, sigChan chan os.Signal) {
sig := <-sigChan
fmt.Printf("app shutdown started with %v signal", sig)
cancel()
}
package app
import (
"api/internal/server"
"context"
"errors"
"fmt"
"time"
)
type App struct {
srv server.Server
}
func New(srv server.Server) App {
return App{srv: srv}
}
func (app App) Start(ctx context.Context) error {
doneChan := make(chan struct{})
go shutdown(ctx, doneChan, app)
// Start HTTP server
if err := a.srv.Start(); err != nil {
return errors.New("failed to start HTTP server")
}
// Start DB server
// ...
<-doneChan
return nil
}
func shutdown(ctx context.Context, doneChan chan<- struct{}, app App) {
<-ctx.Done()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Shutdown HTTP server
err := app.srv.Shutdown(ctx)
if err != nil {
fmt.Print("some active HTTP connections are interrupted at shutdown")
} else {
fmt.Print("no HTTP connections are interrupted at shutdown")
}
// Shutdown DB server
// ...
close(doneChan)
}
编辑
我做了一些goroutine分析,发现如下。我不确定结果是否正常!我需要你的意见
- 对于
-pprof堆栈跟踪为。但是,如果我同时发送10个请求,则它介于17和22之间运行时,单个请求的响应返回6。NumGoroutine()
- 我认为这是正常的,因为我正在使用
,它会对每个请求生效httprouter
你没有泄漏任何goroutines。你正确地截获了信号。惯用的围棋?可能我倾向于为
listenSignals
之类的东西编写匿名函数,但我就是这样。感谢@sberry,如果堆栈跟踪查找有助于识别任何问题,我还会在文章的底部添加堆栈跟踪查找。