func()

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
}