2 回答

TA貢獻(xiàn)1824條經(jīng)驗(yàn) 獲得超5個(gè)贊
要在主 goroutine 中等待 Shutdown 完成,請(qǐng)從該 goroutine 調(diào)用 Shutdown。消除通道和額外的 goroutine。
listener, _ := net.Listen("tcp", "localhost:0")
fmt.Printf("Listening on http://%v\n", listener.Addr())
mux := http.NewServeMux()
mux.HandleFunc("/", handleIndex)
server := &http.Server{Handler: mux}
go func() {
fmt.Println("Starting server...")
err := server.Serve(listener)
if err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
time.Sleep(5 * time.Second) // delay here just for example of "long-running" server
// Shutdown and wait for server to complete.
server.Shutdown(context.Background())
如果要限制 Shutdown 等待服務(wù)器關(guān)閉的時(shí)間,請(qǐng)?zhí)鎿Qcontext.Background()為使用截止日期創(chuàng)建的上下文。

TA貢獻(xiàn)1934條經(jīng)驗(yàn) 獲得超2個(gè)贊
理論上,我可以通過(guò)調(diào)用 server.Shutdown(ctx) 來(lái)阻止它,但現(xiàn)在 import "context" 中的任何可用上下文似乎都不能提供我想要的。我希望能夠等到干凈關(guān)閉完成,然后繼續(xù)我的代碼。
這意味著您應(yīng)該傳遞一個(gè)不會(huì)超時(shí)的上下文。既不context.Background()也不context.TODO()超時(shí),因此是合適的(真的,見(jiàn)下文)。您是否使用其中一個(gè)取決于您是否計(jì)劃超時(shí)關(guān)閉(您應(yīng)該防止粗糙的客戶(hù)端阻止您關(guān)閉您的服務(wù)器)。
我的理解是我應(yīng)該能夠 <- ctx.Done() 來(lái)實(shí)現(xiàn)這一點(diǎn),但我已經(jīng)嘗試了 context.Background() 和 context.TODO() 并且似乎都沒(méi)有“觸發(fā)”ctx.Done(),我最終永遠(yuǎn)阻塞了。其他上下文選項(xiàng)似乎是基于時(shí)間的。
嗯,這個(gè)是錯(cuò)的。也context.Background()不會(huì)context.TODO()關(guān)閉它們Done,因?yàn)樗鼈儾粫?huì)超時(shí)。但是不需要 等待 done: 是一個(gè)正常的函數(shù),一旦服務(wù)器實(shí)際正確關(guān)閉(這就是你想要的)或上下文超時(shí),它就會(huì)返回。無(wú)論如何只是返回。server.Shutdownserver.Shutdown
一個(gè)簡(jiǎn)單的
server.Shutdown(context.TODO())
是你想要的。(現(xiàn)在,從長(zhǎng)遠(yuǎn)來(lái)看:傳遞一個(gè)在很長(zhǎng)但有限的時(shí)間后超時(shí)的上下文。)
但是無(wú)論如何,您的代碼看起來(lái)都很可疑:您的 func startHTTPServer 沒(méi)有正確處理錯(cuò)誤:不是啟動(dòng)錯(cuò)誤,也不是停止錯(cuò)誤。如果您的服務(wù)器沒(méi)有啟動(dòng),您將無(wú)法停止它,您的代碼只會(huì)吞下錯(cuò)誤。犯錯(cuò)也很活潑。您的問(wèn)題可能不是來(lái)自傳遞給 server.Shutdown 的上下文,而是來(lái)自其他地方。
問(wèn)題是你的代碼沒(méi)有等待 server.Shutdown 返回,因?yàn)檫@個(gè)函數(shù)是在一個(gè) goroutine 中啟動(dòng)的,沒(méi)有任何同步回 startHTTPServer 的調(diào)用者:不要那樣做。真的: server.Shutdown 的上下文不是問(wèn)題。
以下是未經(jīng)測(cè)試的代碼,它稍微克服了這些問(wèn)題。正如您在所有 TOOD 中看到的那樣,它還沒(méi)有準(zhǔn)備好生產(chǎn)。
// startHTTPServer is a helper function to start a server and returns
// a channel to stop the server and a channel reporting errors during
// starting/stopping the server or nil if the server was shut down
// properly
func startHTTPServer(listener net.Listener, handler http.Handler) (stop chan bool, problems chan error) {
stop, problems = make(chan bool), make(chan error)
server := &http.Server{Handler: handler} // TODO: set timeouts
go func() {
fmt.Println("Starting server...")
err := server.Serve(listener)
if err != http.ErrServerClosed {
problems <- err // TODO: tag/classify as startup error
}
}()
go func() {
select {
case <-stop:
fmt.Println("Stop channel closed; stopping server...")
err := server.Shutdown(context.TODO())
fmt.Println("Stopped.")
problems <- err // TODO: tag/classify as shutdown error
case e := <-problems:
problems <- e // resend, this error is not for us
return // stop waiting for stop as server did not start anyway.
}
}()
return stop, problems
}
其他解決方案也是可能的,例如返回單獨(dú)的啟動(dòng)和關(guān)閉錯(cuò)誤通道等。
- 2 回答
- 0 關(guān)注
- 146 瀏覽
添加回答
舉報(bào)