Skip to content

Commit

Permalink
flathttp/error, flathttp/server: cleanup error handling, and separate…
Browse files Browse the repository at this point in the history
… errors and error utils into a separate file
  • Loading branch information
lithdew committed May 24, 2020
1 parent b00748d commit 3c3d816
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 53 deletions.
25 changes: 25 additions & 0 deletions flathttp/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package flathttp

import (
"errors"
"io"
"net"
"net/http"
)

var ErrAlreadyListening = errors.New("already listening")

func eof(err error) error {
var op *net.OpError

switch {
case errors.As(err, &op) && op.Err.Error() == "use of closed network connection":
return nil
case errors.Is(err, http.ErrServerClosed):
return nil
case errors.Is(err, io.EOF):
return nil
default:
return err
}
}
77 changes: 24 additions & 53 deletions flathttp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ import (
"context"
"errors"
"fmt"
"io"
"net"
"net/http"
"strings"
"sync"
"time"
)

var DefaultShutdownTimeout = 5 * time.Second

var ErrAlreadyListening = errors.New("already listening")

type Server struct {
cfg Config
srv *http.Server
Expand All @@ -23,7 +21,7 @@ type Server struct {
wg sync.WaitGroup // all served goroutines
lm sync.Mutex // lifecycle mutex\
em sync.Mutex // errors mutex
errs []error // errors
errs []string // errors
}

func NewServer(cfg *Config) *Server {
Expand All @@ -37,18 +35,18 @@ func NewServer(cfg *Config) *Server {
return srv
}

func (s *Server) Start() []error {
func (s *Server) Start() error {
s.lm.Lock()
defer s.lm.Unlock()

err := s.start()
if err != nil {
return append([]error{err}, s.stop()...)
return s.stop()
}
return nil
}

func (s *Server) Stop() []error {
func (s *Server) Stop() error {
s.lm.Lock()
defer s.lm.Unlock()

Expand Down Expand Up @@ -119,24 +117,20 @@ func (s *Server) listen(a Addr) error {
s.wg.Add(1)
go func() {
defer s.wg.Done()

err := eof(srv.Serve(ln))
if err == nil {
return
if err != nil {
err := fmt.Sprintf("unexpected error finishing serving %s (err=%q)", a.Addr, err)
s.em.Lock()
s.errs = append(s.errs, err)
s.em.Unlock()
}

err = fmt.Errorf("flathttp [%s] (serve error): %w", a.Addr, err)

s.em.Lock()
s.errs = append(s.errs, err)
s.em.Unlock()
}()

return nil
}

func (s *Server) stop() []error {
var errs []error
func (s *Server) stop() error {
var errs []string

// Gracefully shutdown the server.

Expand All @@ -149,12 +143,18 @@ func (s *Server) stop() []error {

err := s.srv.Shutdown(ctx)
if err != nil {
errs = append(errs, fmt.Errorf("flathttp: failed to gracefully shutdown the server: %w", err))
errs = append(errs, fmt.Sprintf("failed to gracefully shutdown the server (err=%q)", err.Error()))
}

<-ctx.Done()

errs = append(errs, s.close()...)
for addr, ln := range s.lns {
err := eof(ln.Close())
if err != nil {
err := fmt.Sprintf("[%s] failed to close listener (err=%q)", addr, err)
errs = append(errs, err)
}
}

if cancel != nil {
cancel()
Expand All @@ -163,46 +163,17 @@ func (s *Server) stop() []error {
// Wait until all listeners are closed, and if errors rise up, include them in the result.

s.wg.Wait()

errs = append(errs, s.errs...)
s.errs = s.errs[:0]
s.cfg.reset()

s.srv = nil

for addr := range s.lns {
delete(s.lns, addr)
}

errs = append(errs, s.errs...)
s.errs = s.errs[:0]

return errs
}

func eof(err error) error {
var op *net.OpError

switch {
case errors.As(err, &op) && op.Err.Error() == "use of closed network connection":
if len(errs) == 0 {
return nil
case errors.Is(err, http.ErrServerClosed):
return nil
case errors.Is(err, io.EOF):
return nil
default:
return err
}
}

func (s *Server) close() []error {
var errs []error

for addr, ln := range s.lns {
err := eof(ln.Close())
if err != nil {
err = fmt.Errorf("flathttp [%s] (listener close): %w", addr, err)
errs = append(errs, err)
}
}

return errs
return fmt.Errorf("flathttp: failed to stop server: %s", strings.Join(errs, ", "))
}

0 comments on commit 3c3d816

Please sign in to comment.