Instead of trying to restart the server, switch the handler: package main
import ( "fmt" "io/ioutil" "log" "net/http" "strconv" ) // Some state so we can show the old handler is in effect... type Foo struct { SomeVar int } func (f *Foo) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Printf("In handler wrapper, f = %p\n", f) w.Write([]byte(strconv.Itoa(f.SomeVar))) } type switchable struct { h http.Handler } func (s *switchable) ServeHTTP(w http.ResponseWriter, r *http.Request) { s.h.ServeHTTP(w, r) } func main() { log.SetFlags(log.Lshortfile) f1 := &Foo{SomeVar: 1} f2 := &Foo{SomeVar: 2} handler := &switchable{f1} go func() { log.Fatalln(http.ListenAndServe("0.0.0.0:8090", handler)) }() fmt.Println(doRequest()) handler.h = f2 fmt.Println(doRequest()) } func doRequest() string { client := &http.Client{} req, err := http.NewRequest("GET", "http://0.0.0.0:8090", nil) if err != nil { log.Fatalln(err) } resp, err := client.Do(req) if err != nil { log.Fatalln(err) } bytes, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } return string(bytes) } Output: $ go run main.go In handler wrapper, f = 0xc420060fa0 1 In handler wrapper, f = 0xc420060fa8 2 I'm not sure if there is a race condition here or not... On Tuesday, April 18, 2017 at 7:02:17 AM UTC+2, Ken Simon wrote: > > Hello golang-nuts! > > I have some code that creates a short-lived HTTP server, and I'm trying to > write tests for it. I'm hitting a case where HTTP handlers seem to stick > around even though I'm creating a brand new `http.ServeMux`, `http.Server`, > and `net.Listener` objects. How do I get rid of old handlers? > > Here's a semi-simple reproducible case: > > package main > > import ( > "fmt" > "io/ioutil" > "net" > "net/http" > "os" > "strconv" > "time" > ) > > // Some state so we can show the old handler is in effect... > type Foo struct { > SomeVar int > } > > func (f *Foo) Serve(addr string) (net.Listener, error) { > l, err := net.Listen("tcp", addr) > if err != nil { > return nil, err > } > mux := http.NewServeMux() > mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { > fmt.Printf("In handler wrapper, f = %p\n", f) > w.Write([]byte(strconv.Itoa(f.SomeVar))) > }) > srv := &http.Server{ > Handler: mux, > } > > go srv.Serve(l) > return l, nil > } > > func main() { > f1 := &Foo{SomeVar: 1} > f2 := &Foo{SomeVar: 2} > > l, err := f1.Serve("0.0.0.0:8090") > if err != nil { > fmt.Println(err) > os.Exit(1) > } > fmt.Println(doRequest()) > l.Close() > // Ok it didn't actually close, wait a bit or it'll show the address as > // already in use... > time.Sleep(1 * time.Second) > > l, err = f2.Serve("0.0.0.0:8090") > if err != nil { > fmt.Println(err) > os.Exit(1) > } > fmt.Println(doRequest()) > l.Close() > } > > func doRequest() string { > client := &http.Client{} > req, _ := http.NewRequest("GET", "http://0.0.0.0:8090", nil) > resp, _ := client.Do(req) > bytes, _ := ioutil.ReadAll(resp.Body) > return string(bytes) > } > > Output: > > $ go run main.go > In handler wrapper, f = 0xc42000d200 > 1 > In handler wrapper, f = 0xc42000d200 > 1 > > Note the pointer to the method receiver is the same in both cases, > indicating the old ServeMux is still handling the new request... (boy did > it take me a long time to figure out what was going on in a non-trivial > codebase...) > > What's happening here? Is the old http.Server still "attached" to the > tcp.Listener? What can I do to fix this? > > Thanks so much! > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.