1 回答
TA贡献1752条经验 获得超4个赞
您选择了一个不好的示例,因为您通常会重用数据库连接,而不是每次使用时打开和关闭一个数据库连接。因此,您可以将数据库连接传递给使用它的函数,并在调用者中进行资源管理,而不需要资源管理器:
// Imports etc omitted for the sake of readability
func PingHandler(db *sql.DB) http.Handler (
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := db.ping(); err != nil {
http.Error(w,e.Error(),500)
}
})
)
func main(){
db,_ := sql.Open("superdb",os.Getenv("APP_DBURL"))
// Note the db connection will only be closed if main exits.
defer db.Close()
// Setup the server
http.Handle("/ping", PingHandler(db))
server := &http.Server{Addr: ":8080"}
// Create a channel for listening on SIGINT, -TERM and -QUIT
stop := make(chan os.Signal, 1)
// Register channel to be notified on said signals
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func(){
// When we get the signal...
<- stop
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
// ... we gracefully shut down the server.
// That ensures that no new connections, which potentially
// would use our db connection, are accepted.
if err := server.Shutdown(ctx); err != nil {
// handle err
}
}
// This blocks until the server is shut down.
// AFTER it is shut down, main exits, the deferred calls are executed.
// In this case, the database connection is closed.
// And it is closed only after the last handler call which uses the connection is finished.
// Mission accomplished.
server.ListenAndServe()
}
因此,在这个示例中,不需要资源管理器,而且老实说,我想不出真正需要资源管理器的示例。在极少数情况下,我需要类似的东西,我使用了sync.Pool
.
但是,对于 gRPC 客户端连接,也无需维护池:
[...]但是,ClientConn 应该自行管理连接,因此如果连接断开,它将自动重新连接。如果您有多个后端,则可以连接到其中多个后端并在它们之间实现负载平衡。[...]
因此,同样的原则适用:创建一个连接(池),根据需要传递它,确保在完成所有工作后关闭它。
不要将资源管理隐藏在其他地方,而是尽可能靠近使用资源的代码并尽可能明确地管理资源。
- 1 回答
- 0 关注
- 104 浏览
添加回答
举报