由于种种原因,我觉得http.ListenAndServe不适合我的需要。
我需要能够确定绑定的地址和端口(即使用时":0"),所以我引入了一个net.Listener,读取listener.Addr()然后传递给http.Serve(listener, nil)。
然后我需要能够使用不同的 URL 处理程序运行两个 HTTP 服务器,所以我引入了一个http.NewServeMux(),添加了必要的mux.HandleFunc("/path", fn)处理程序,并传递为http.Serve(listener, mux).
然后我需要能够干净地停止这些服务器,并关闭任何连接,独立于主程序本身,所以现在我介绍了&http.Server{Handler: mux}哪些我可以go func() { server.Serve(listener) }()。
理论上,我可以通过调用来阻止它server.Shutdown(ctx),但现在import "context"似乎没有一个可用的上下文提供我想要的。我希望能够等到干净关闭完成,然后继续我的代码。
我的理解是我应该能够<- ctx.Done()实现这一点,但我已经尝试了两者context.Background(),context.TODO()而且似乎都没有“触发” ctx.Done(),我最终永远阻塞了。其他context选项似乎是基于时间的。
如果我不等待或通过,似乎完成得太快,我看不到任何东西实际上是关闭的()nilserver.Shutdown(ctx)runtime.Numgoroutine() != 1
我可以time.Sleep(duration)任意持续一段时间,但我不想要任意持续时间。我想知道server.Shutdown已经干净地完成了。
package main
import (
"fmt"
"net"
"net/http"
"runtime"
"time"
)
func main() {
var err error
listener, err := net.Listen("tcp", "localhost:0")
fmt.Printf("Listening on http://%v\n", listener.Addr())
mux := http.NewServeMux()
mux.HandleFunc("/", handleIndex)
stop, err := startHTTPServer(listener, mux)
d, _ := time.ParseDuration("5s")
time.Sleep(d) // delay here just for example of "long-running" server
close(stop) // closing the channel returned by my helper should trigger shutdown
time.Sleep(d) // if this delay is here, I see the "Stopped" message
if err != nil {
panic(err)
}
fmt.Printf("End of program, active goroutines: %v", runtime.NumGoroutine())
}
我都试过了context.Background()和context.TODO()。我试过new(context.Context)了,但那抛出了一个SIGSEGV. 我试过nil了,根本不用等。
我尝试添加 a sync.WaitGroupand 调用wg.Wait()而不是 second time.Sleep(d),但我仍然需要等到server.Shutdown()完成后再调用wg.Done()(并且defer wg.Done()调用它太早了)。
我觉得,对于 Contexts、WaitGroups 等,我只是在代码中添加了一些杂乱无章的东西,而没有真正理解为什么它们是必要的。
等待server.Shutdown完成的正确、干净、惯用的方法是什么?
红糖糍粑
沧海一幻觉
撒科打诨
随时随地看视频慕课网APP
相关分类