| 31 | } |
| 32 | |
| 33 | func (s *server) RunWithLifecycle(lifecycle service.Lifecycle) error { |
| 34 | s.lock.Lock() |
| 35 | if s.srv != nil { |
| 36 | return fmt.Errorf("server is already running") |
| 37 | } |
| 38 | s.srv = &goHttp.Server{ |
| 39 | Addr: s.config.Listen, |
| 40 | Handler: s.handler, |
| 41 | TLSConfig: s.tlsConfig, |
| 42 | ErrorLog: log.New(s.goLogger, "", 0), |
| 43 | } |
| 44 | defer func() { |
| 45 | s.lock.Lock() |
| 46 | s.srv = nil |
| 47 | s.lock.Unlock() |
| 48 | }() |
| 49 | var err error |
| 50 | |
| 51 | ln, err := net.Listen("tcp", s.srv.Addr) |
| 52 | if err != nil { |
| 53 | s.lock.Unlock() |
| 54 | return message.Wrap(err, message.EHTTPListenFailed, "Failed to listen on %s", s.srv.Addr) |
| 55 | } |
| 56 | defer func() { _ = ln.Close() }() |
| 57 | var url string |
| 58 | if s.srv.TLSConfig != nil { |
| 59 | url = fmt.Sprintf("https://%s", s.config.Listen) |
| 60 | } else { |
| 61 | url = fmt.Sprintf("http://%s", s.config.Listen) |
| 62 | } |
| 63 | s.onReady(url) |
| 64 | lifecycle.Running() |
| 65 | s.lock.Unlock() |
| 66 | serverFinished := make(chan struct{}, 1) |
| 67 | go func() { |
| 68 | select { |
| 69 | case <-lifecycle.Context().Done(): |
| 70 | s.lock.Lock() |
| 71 | if s.srv == nil { |
| 72 | s.lock.Unlock() |
| 73 | return |
| 74 | } |
| 75 | srv := s.srv |
| 76 | s.lock.Unlock() |
| 77 | _ = srv.Shutdown(lifecycle.ShutdownContext()) |
| 78 | case <-serverFinished: |
| 79 | } |
| 80 | }() |
| 81 | if s.srv.TLSConfig != nil { |
| 82 | err = s.srv.ServeTLS(ln, "", "") |
| 83 | } else { |
| 84 | err = s.srv.Serve(ln) |
| 85 | } |
| 86 | serverFinished <- struct{}{} |
| 87 | if err != nil && !errors.Is(err, goHttp.ErrServerClosed) { |
| 88 | return err |
| 89 | } |
| 90 | return nil |