Storing an *http.Server in a struct field


Storing an *http.Server in a struct field

I am currently building an HTTP server package that starts and gracefully stops multiple HTTP servers.

package http import ( "context" "net/http" "sync" "time" ) type ServerConfiguration struct { Addr1 string Addr2 string server1 *http.Server server2 *http.Server } func (c ServerConfiguration) Run() error { c.server1 = &http.Server{Addr: c.Addr1} c.server2 = &http.Server{Addr: c.Addr2} var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() err := c.server1.ListenAndServe() if err != http.ErrServerClosed { // @TODO } }() go func() { defer wg.Done() err := c.server2.ListenAndServe() if err != http.ErrServerClosed { // @TODO } }() wg.Wait() return nil } func (c ServerConfiguration) Shutdown() error { var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := c.server1.Shutdown(ctx); err != nil { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := c.server2.Shutdown(ctx); err != nil { // @TODO } } }() go func() { defer wg.Done() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := c.server2.Shutdown(ctx); err != nil { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := c.server1.Shutdown(ctx); err != nil { // @TODO } } }() wg.Wait() return nil } 

I thought I could now just create a new ServerConfiguration, run Run() on it and listen for a SIGINT or SIGTERM in a goroutine that then runs Shutdown().

package main import ( "os" "os/signal" "syscall" myhttp "foo/http" ) func main() { c := myhttp.ServerConfiguration{ Addr1: ":https", Addr2: ":http", } idleConnsClosed := make(chan struct{}) go func() { sigint := make(chan os.Signal, 1) signal.Notify(sigint, syscall.SIGINT, syscall.SIGTERM) <-sigint if err := c.Shutdown(); err != nil { // @TODO } close(idleConnsClosed) }() err := c.Run() if err != nil { // @TODO } <-idleConnsClosed os.Exit(0) } 

But that doesn't seem to work. Instead I am getting a segfault because both servers in ServerConfiguration are nil in Shutdown(). I know that this is related to how pointers in Go work differently compared to most other languages, but I can't figure out how to fix this package.

Thanks in advance!

Submitted February 23, 2018 at 05:00PM by marcelsiegert
via reddit http://ift.tt/2oqtnOg

Advertisements