Run runs the HTTP server until ctx is canceled. The done channel has an error written to when the HTTP server is terminated, and can be nil or not nil.
(ctx context.Context, ready chan<- struct{}, done chan<- struct{})
| 11 | // The done channel has an error written to when the HTTP server |
| 12 | // is terminated, and can be nil or not nil. |
| 13 | func (s *Server) Run(ctx context.Context, ready chan<- struct{}, done chan<- struct{}) { |
| 14 | server := http.Server{ |
| 15 | Addr: s.address, |
| 16 | Handler: s.handler, |
| 17 | ReadHeaderTimeout: s.readHeaderTimeout, |
| 18 | ReadTimeout: s.readTimeout, |
| 19 | } |
| 20 | |
| 21 | crashed := make(chan struct{}) |
| 22 | shutdownDone := make(chan struct{}) |
| 23 | listenCtx, listenCancel := context.WithCancel(ctx) |
| 24 | go func() { |
| 25 | defer close(shutdownDone) |
| 26 | defer listenCancel() |
| 27 | select { |
| 28 | case <-ctx.Done(): |
| 29 | case <-crashed: |
| 30 | return |
| 31 | } |
| 32 | |
| 33 | shutdownCtx, cancel := context.WithTimeout( |
| 34 | context.Background(), s.shutdownTimeout) |
| 35 | defer cancel() |
| 36 | if err := server.Shutdown(shutdownCtx); err != nil { |
| 37 | s.logger.Error("http server failed shutting down within " + |
| 38 | s.shutdownTimeout.String()) |
| 39 | } |
| 40 | }() |
| 41 | |
| 42 | listenConfig := &net.ListenConfig{} |
| 43 | listener, err := listenConfig.Listen(listenCtx, "tcp", s.address) |
| 44 | if err != nil { |
| 45 | close(s.addressSet) |
| 46 | close(crashed) // stop shutdown goroutine |
| 47 | <-shutdownDone |
| 48 | s.logger.Error(err.Error()) |
| 49 | close(done) |
| 50 | return |
| 51 | } |
| 52 | |
| 53 | s.address = listener.Addr().String() |
| 54 | close(s.addressSet) |
| 55 | |
| 56 | // note: no further write so no need to mutex |
| 57 | s.logger.Info("http server listening on " + s.address) |
| 58 | close(ready) |
| 59 | |
| 60 | err = server.Serve(listener) |
| 61 | |
| 62 | if err != nil && !errors.Is(ctx.Err(), context.Canceled) { |
| 63 | // server crashed |
| 64 | close(crashed) // stop shutdown goroutine |
| 65 | } else { |
| 66 | err = nil |
| 67 | } |
| 68 | <-shutdownDone |
| 69 | if err != nil { |
| 70 | s.logger.Error(err.Error()) |