in app.go [224:343]
func (a *theApp) Run() error {
var limiter *netutil.Limiter
if a.config.General.MaxConns > 0 {
limiter = netutil.NewLimiterWithMetrics(
a.config.General.MaxConns,
metrics.LimitListenerMaxConns,
metrics.LimitListenerConcurrentConns,
metrics.LimitListenerWaitingConns,
)
}
// Use a common pipeline to use a single instance of each handler,
// instead of making two nearly identical pipelines
commonHandlerPipeline, err := a.buildHandlerPipeline()
if err != nil {
return fmt.Errorf("unable to configure pipeline: %w", err)
}
proxyHandler := ghandlers.ProxyHeaders(commonHandlerPipeline)
httpHandler := a.httpInitialMiddleware(commonHandlerPipeline)
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
defer stop()
eg, ctx := errgroup.WithContext(ctx)
var servers []*http.Server
// Listen for HTTP
for _, addr := range a.config.ListenHTTPStrings.Split() {
s := a.listen(
eg,
addr,
httpHandler,
errortracking.WithField("listener", request.SchemeHTTP),
withLimiter(limiter),
)
servers = append(servers, s)
}
// Listen for HTTPS
for _, addr := range a.config.ListenHTTPSStrings.Split() {
tlsConfig, err := a.getTLSConfig()
if err != nil {
return fmt.Errorf("unable to retrieve tls config: %w", err)
}
s := a.listen(
eg,
addr,
httpHandler,
errortracking.WithField("listener", request.SchemeHTTPS),
withLimiter(limiter),
withTLSConfig(tlsConfig),
)
servers = append(servers, s)
}
// Listen for HTTP proxy requests
for _, addr := range a.config.ListenProxyStrings.Split() {
s := a.listen(
eg,
addr,
proxyHandler,
errortracking.WithField("listener", "http proxy"),
withLimiter(limiter),
)
servers = append(servers, s)
}
// Listen for HTTPS PROXYv2 requests
for _, addr := range a.config.ListenHTTPSProxyv2Strings.Split() {
tlsConfig, err := a.getTLSConfig()
if err != nil {
return fmt.Errorf("unable to retrieve tls config: %w", err)
}
s := a.listen(
eg,
addr,
httpHandler,
errortracking.WithField("listener", "https proxy"),
withLimiter(limiter),
withTLSConfig(tlsConfig),
withProxyV2(),
)
servers = append(servers, s)
}
// Serve metrics for Prometheus
if a.config.Metrics.Address != "" {
s := a.listenMetrics(eg, a.config.Metrics)
servers = append(servers, s)
}
<-ctx.Done()
var result *multierror.Error
for _, srv := range servers {
ctx, cancel := context.WithTimeout(context.Background(), a.config.General.ServerShutdownTimeout)
if err := srv.Shutdown(ctx); err != nil {
result = multierror.Append(result, err)
}
cancel()
}
if err := eg.Wait(); err != nil {
result = multierror.Append(result, err)
}
if result.ErrorOrNil() != nil {
errortracking.CaptureErrWithStackTrace(result.ErrorOrNil())
return result.ErrorOrNil()
}
return nil
}