| 61 | } |
| 62 | |
| 63 | func (s *Server) serve(ctx context.Context, ln net.Listener) { |
| 64 | defer s.done.Done() |
| 65 | errCh := make(chan error) |
| 66 | go func() { |
| 67 | if err := s.srv.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) { |
| 68 | errCh <- err |
| 69 | } |
| 70 | close(errCh) |
| 71 | }() |
| 72 | // Wait for either the context to cancel or for the server to exit. |
| 73 | var reason string |
| 74 | var srvErr error |
| 75 | select { |
| 76 | case srvErr = <-errCh: |
| 77 | reason = "server error" |
| 78 | case <-ctx.Done(): |
| 79 | reason = "context closed" |
| 80 | if err := context.Cause(ctx); !errors.Is(err, context.Canceled) { |
| 81 | reason = err.Error() |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | s.logger.Info("Shutting down", zap.String("reason", reason), zap.Error(srvErr)) |
| 86 | timeout, cancel := context.WithTimeout(context.Background(), ShutdownTimeout) |
| 87 | defer cancel() |
| 88 | err := s.srv.Shutdown(timeout) |
| 89 | if errors.Is(err, http.ErrServerClosed) { |
| 90 | err = srvErr |
| 91 | } else if errors.Is(err, context.DeadlineExceeded) { |
| 92 | s.logger.Warn("Server shutdown deadline exceeded", zap.Duration("duration", ShutdownTimeout)) |
| 93 | if clsErr := s.srv.Close(); clsErr != nil { |
| 94 | err = clsErr |
| 95 | } |
| 96 | } |
| 97 | s.logger.Info("Closed", zap.Error(err)) |
| 98 | s.err = err |
| 99 | } |