Properly closing http.Serve

717 views
Skip to first unread message

Joe Pond

unread,
Jan 11, 2013, 4:59:31 PM1/11/13
to golan...@googlegroups.com
I created a small program which allows users to put up files for a one time (or more) download.  Currently I have something along the lines of

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
     // archive and send files to user
     if onLastDownload() {
        l.Close()
    }
}

http.Serve(l, nil)

The problem is that when I call l.Close(), http.Serve returns an error, leading to main exiting, which closes the connection.  Sleeping at the end of main for 1 second allows for the connection to be closed, but this seems like a horrible solution.

What is a good way to close the server and allow existing requests to finish?

zeebo

unread,
Jan 12, 2013, 11:17:41 AM1/12/13
to golan...@googlegroups.com
You could have the request send down a channel when it was finished and then have main receive from that channel.

In general, you need to synchronize the ending of all your outstanding requests with main exiting, so cause that to happen.

minux

unread,
Jan 12, 2013, 11:32:19 AM1/12/13
to Joe Pond, golan...@googlegroups.com

Joseph Pond

unread,
Jan 13, 2013, 3:11:06 AM1/13/13
to golan...@googlegroups.com
I tried tried using sync.WaitGroup with the handlers; however this did not
resolve the problem. If you look at the net/http/server.go http.conn.serve()
method, you can see the handler is called towards the end. After the handler
returns, it proceeds to finish the request and wrap up the connection. This
means that, even after all handlers have finished, exiting main can prematurely
terminate the http.conn.serve() goroutines.

My solution for this was to simply write a net.Listener and net.Conn wrapper
which would keep track of open connections. Once the listener is closed, main
simply waits for the remaining connections to be closed.

Closing the server through closing the connection seems like pulling the carpet
beneat its feet. I think some sort of method for gracefully stopping the
server would be a great addition.

Patrick Higgins

unread,
Jan 14, 2013, 6:56:55 PM1/14/13
to golan...@googlegroups.com

On Sunday, January 13, 2013 1:11:06 AM UTC-7, Joe Pond wrote:
My solution for this was to simply write a net.Listener and net.Conn wrapper
which would keep track of open connections.  Once the listener is closed, main
simply waits for the remaining connections to be closed.
This works great for me! I have put my wrappers at http://play.golang.org/p/x1Cai1qBTc for review/reference.
Closing the server through closing the connection seems like pulling the carpet
beneat its feet.  I think some sort of method for gracefully stopping the
server would be a great addition.
Agreed. I am tired of seeing "accept tcp [::]:8080: use of closed network connection" in my logs.

Dave Cheney

unread,
Jan 14, 2013, 7:02:57 PM1/14/13
to Patrick Higgins, golan...@googlegroups.com
Please consider raising this as a feature request on the Go issue tracker.
> --
>
>

John Jeffery

unread,
Jan 16, 2013, 3:11:55 AM1/16/13
to golan...@googlegroups.com
This looks like a great solution. Can I ask though, what happens to keep-alive connections? Do you have to wait for a timeout on all keep-alive connections before main will exit? This might take a while. Would a graceful shutdown need some way to force any keep-alive connections to close as soon as possible?

minux

unread,
Jan 16, 2013, 5:15:32 AM1/16/13
to John Jeffery, golan...@googlegroups.com
On Wed, Jan 16, 2013 at 4:11 PM, John Jeffery <jjef...@sp.com.au> wrote:
This looks like a great solution. Can I ask though, what happens to keep-alive connections? Do you have to wait for a timeout on all keep-alive connections before main will exit? This might take a while. Would a graceful shutdown need some way to force any keep-alive connections to close as soon as possible?
You set ReadTimeout for the http.Server struct so that keep-alive'd idle connection will
eventually be closed within certain time limit.

Or, you can use (*Transport) CloseIdleConnections() to force close all idle connections.
Reply all
Reply to author
Forward
0 new messages