Reputation: 2703
I need to implement a server in Golang. I'm using the net
package for this purpose but I do not understand how to break out from the accept
loop gracefully.
So looking at the example from the net
package:
ln, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
for {
conn, err := ln.Accept()
if err != nil {
// handle error
}
go handleConnection(conn)
}
I want to do something more along the lines of:
for {
select {
case <-done:
break
case conn, err := <-ln.Accept():
if err != nil {
break
}
...
}
I other words, I want to be able to terminate the program gracefully somehow.
Upvotes: 4
Views: 1379
Reputation: 22147
The best practice, with any service, to ensure a clean shutdown is to ensure each part of the service supports cancelation. Adding context.Context support is the recommended way to achieve this.
So first, ensure your net.Listener
does not hang on rogue client connection. So to add context.Context
support:
var lc net.ListenConfig
ln, err := lc.Listen(ctx, "tcp", ":8080")
Canceling ctx
will break any rogue client connection here that may be blocking during handshake.
EDIT:
To ensure we can break out of the Listen()
call while it is blocked waiting, one can leverage the same ctx
state and (as noted in a previous, now deleted, answer) close the connection when a cancelation event is detected:
go func() {
<-ctx.Done()
log.Println("shutting service down...")
ln.Close()
}()
Working example: https://play.golang.org/p/LO1XS4jBQ02
Upvotes: 9