Go Context with http.server

huangapple go评论81阅读模式
英文:

Go Context with http.server

问题

为了测试我正在编写的服务器,我希望能够在测试框架中启动和停止它。

为了做到这一点,我希望能够将context包与http.Server结构体集成在一起。当我调用Done函数并且ctx.Done()通道返回某个值时,我希望能够停止服务器。

我希望做的是修改http.Server.Serve()方法,接受一个context.Context并在每次for循环迭代时检查它是否完成,像这样:

func (srv *server) Serve(ctx context.Context, l net.Listener) error {
    defer l.Close()
    var tempDelay time.Duration // how long to sleep on accept failure
    for {
        select {
        case <-ctx.Done():
            return nil
        default:
        }
        ... 其余部分与原始代码相同

然而,如果我想在for循环内添加该检查,我似乎需要重写很多方法,因为该方法调用其他私有方法(如http.server.srv),而这些私有方法又调用其他私有方法......

我还注意到,当监听器的Accept()方法返回错误时,for循环将停止。

然而,我似乎找不到一种方法来使监听器的accept方法输出错误,而不需要访问其私有方法。

如果我不得不复制粘贴一半的http库代码才能让服务器使用context包停止,那么我似乎在做一些非常愚蠢和错误的事情。

我知道有很多解决方案可以支持ServeHTTP函数的上下文取消,但这不是我所说的。我想将上下文传递给整个服务器,而不仅仅是每个传入的请求。

这是否完全不可能?

英文:

In order to test a server that I am writing, I want to be able to start and stop it in the testing framework.

To do so, I am hoping I can integrate the context package in with the http.Server struct. I want to be able to stop the server when I call the Done function and the ctx.Done() channel returns something.

What I would love to do would be to just modify the http.Server.Serve() method, to accept a context.Context and check if it is done, on each iteration of the for loop, like this:

func (srv *server) Serve(ctx context.Context, l net.Listener) error {
	defer l.Close()
	var tempDelay time.Duration // how long to sleep on accept failure
	for {
		select {
		case &lt;-ctx.Done():
			return nil
		default:
		}
		... rest is same as original

However it seems like if I wanna add that check inside the for loop, I would have to rewrite a lot of the methods, because this method calls other private methods (like http.server.srv), which in turn call other private methods....

I also notice that the for loop will stop when the Accept() method on the listener returns an error.

However, I can't seem to figure out a way to get a listener to output an error from it's accept method without accessing its private methods as well.

It seems like I am doing something very stupid and wrong if I have to copy and paste half the http library just to let the server stop using the context package.

I know there are lots of solutions around for supporting context canceling for the ServeHTTP function, but that isn't what I am talking about. I wanna pass a context to the whole server, not just to each incoming request.

Is this just impossible?

答案1

得分: 1

使用httptest.Server在测试中创建一个可以启动和停止的服务器。

如果你直接使用http.Server,你可以通过关闭net.Listener来中断Serve循环。当net.Listener被关闭时,任何被阻塞的Accept操作都会被解除阻塞并返回错误。如果Accept返回一个永久性错误,Serve函数也会返回。

英文:

Use httptest.Server to create a server that you can start and stop in tests.

If you do use the http.Server directly, you can break the Serve loop by closing the net.Listener. When a net.Listener is closed, any blocked Accept operations are unblocked and return errors. The Serve function returns if Accept returns a permanent error.

huangapple
  • 本文由 发表于 2015年6月26日 10:24:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/31063874.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定