Howto correctly stop http.Server

4,666 views
Skip to first unread message

Stephan Kountso

unread,
Feb 20, 2012, 10:07:58 AM2/20/12
to golan...@googlegroups.com
I need to stop http server after user request for specific url. During this shutdown I need to:
 1) stop accepting any incomint http requests
 2) wait for all current requests
 3) after all of these I need to run some my functionality (in fact, internal data serialization) and shutdown server (return from main function)

The problem is I couldn't find any way to stop server which is in Serve method. Also I can't just reimplement http.Server::Serve method because it creates internal struct http.conn.

Is there is a solution without rewriting http. package?
Message has been deleted

Jessta

unread,
Feb 20, 2012, 11:19:45 AM2/20/12
to Stephan Kountso, golan...@googlegroups.com
On Tue, Feb 21, 2012 at 2:07 AM, Stephan Kountso <ste...@gmail.com> wrote:
> I need to stop http server after user request for specific url. During this
> shutdown I need to:
>  1) stop accepting any incomint http requests
>  2) wait for all current requests
>  3) after all of these I need to run some my functionality (in fact,
> internal data serialization) and shutdown server (return from main function)

Something like this:
package main
import "net/http"
import "net"
import "sync"

var lis net.Listener

func main(){
var err error
// make our own listener
lis, err = net.Listen("tcp",":8080")
if err != nil {
panic(err)
}
// make our own handler that puts all requests in a wait group.
h := &handler{ServeMux: http.NewServeMux()}

// add a close handlefunc to that handler
h.ServeMux.HandleFunc("/",close)

//listen and serve until listner is closed
http.Serve(lis,h)

//wait here until all current requests complete.
h.w.Wait()
}
type handler struct {
w sync.WaitGroup
*http.ServeMux
}

func (h *handler)ServeHTTP(w http.ResponseWriter, r *http.Request){
h.w.Add(1)
defer h.w.Done()
h.ServeMux.ServeHTTP(w, r)

//important to flush before decrementing the wait group.
//we won't get a chance to once main() ends.
w.(http.Flusher).Flush()
}

func close(w http.ResponseWriter, r *http.Request){
lis.Close()
w.Write([]byte("closed listener"))
}


--
=====================
http://jessta.id.au

Stephan Kountso

unread,
Feb 22, 2012, 5:40:40 AM2/22/12
to golan...@googlegroups.com, Stephan Kountso
Thanks a lot for your replies. I tried to wrap this functionality into StopServer struct: http://pastebin.com/qMi2wkUv

I found some problems in this implementation
  1. waiter.Add(1) is called after creating new go-routine in http.Server::Serve(). Because of this there could be a situation when we initializie new request, then close connection, call waiter.Wait() funciton (and finish it) and only after that call waiter.Add(1). This cause some panics during end of main function
  2. After closing listener, Server::Serve() returns with "invalid argument" error. This seems to me very strange and incorrect situation. Because of this I think it will be better to add callback or something like that to control internal Serve() loop, or ability to create own serve loops.
  3. I really don't like StopServer::Serve() wrapper. We need in runtime change server.Handler. May be it will better to make Serve function to package function, not a Server method?
Reply all
Reply to author
Forward
0 new messages