func run()

in workhorse/cmd/gitlab-workhorse/main.go [193:308]


func run(boot bootConfig, cfg config.Config) error {
	closer, err := startLogging(boot.logFile, boot.logFormat)
	if err != nil {
		return err
	}
	defer closer.Close() //nolint:errcheck

	tracing.Initialize(tracing.WithServiceName("gitlab-workhorse"))
	log.WithField("version", Version).WithField("build_time", BuildTime).Print("Starting")
	fips.Check()

	// Good housekeeping for Unix sockets: unlink before binding
	if boot.listenNetwork == "unix" {
		if err = os.Remove(boot.listenAddr); err != nil && !os.IsNotExist(err) {
			return err
		}
	}

	finalErrors := make(chan error)

	// The profiler will only be activated by HTTP requests. HTTP
	// requests can only reach the profiler if we start a listener. So by
	// having no profiler HTTP listener by default, the profiler is
	// effectively disabled by default.
	_, err = initializePprof(boot.pprofListenAddr, finalErrors)
	if err != nil {
		return err
	}

	var l net.Listener

	monitoringOpts := []monitoring.Option{monitoring.WithBuildInformation(Version, BuildTime)}
	if cfg.MetricsListener != nil {
		l, err = newListener("metrics", *cfg.MetricsListener)
		if err != nil {
			return err
		}
		monitoringOpts = append(monitoringOpts, monitoring.WithListener(l))
	}

	go func() {
		// Unlike http.Serve, which always returns a non-nil error,
		// monitoring.Start may return nil in which case we should not shut down.
		if err = monitoring.Start(monitoringOpts...); err != nil {
			finalErrors <- err
		}
	}()

	secret.SetPath(boot.secretPath)

	log.Info("Using redis/go-redis")

	rdb, err := redis.Configure(&cfg)
	if err != nil {
		log.WithError(err).Error("unable to configure redis client")
	}
	redisKeyWatcher := redis.NewKeyWatcher(rdb)

	if rdb != nil {
		go redisKeyWatcher.Process()
	}

	watchKeyFn := redisKeyWatcher.WatchKey

	if err = cfg.RegisterGoCloudURLOpeners(); err != nil {
		return fmt.Errorf("register cloud credentials: %v", err)
	}

	accessLogger, accessCloser, err := getAccessLogger(boot.logFile, boot.logFormat)
	if err != nil {
		return fmt.Errorf("configure access logger: %v", err)
	}
	defer accessCloser.Close() //nolint:errcheck

	gitaly.InitializeSidechannelRegistry(accessLogger)

	up := wrapRaven(upstream.NewUpstream(cfg, accessLogger, watchKeyFn))

	done := make(chan os.Signal, 1)
	signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)

	listenerFromBootConfig := config.ListenerConfig{
		Network: boot.listenNetwork,
		Addr:    boot.listenAddr,
	}
	var listeners []net.Listener
	oldUmask := syscall.Umask(boot.listenUmask)
	for _, cfg := range append(cfg.Listeners, listenerFromBootConfig) {
		l, err := newListener("upstream", cfg)
		if err != nil {
			return err
		}
		listeners = append(listeners, l)
	}
	syscall.Umask(oldUmask)

	srv := &http.Server{Handler: up}

	for _, l := range listeners {
		go func(l net.Listener) { finalErrors <- srv.Serve(l) }(l)
	}

	select {
	case err := <-finalErrors:
		return err
	case sig := <-done:
		log.WithFields(log.Fields{"shutdown_timeout_s": cfg.ShutdownTimeout.Duration.Seconds(), "signal": sig.String()}).Infof("shutdown initiated")

		ctx, cancel := context.WithTimeout(context.Background(), cfg.ShutdownTimeout.Duration) // lint:allow context.Background
		defer cancel()

		redisKeyWatcher.Shutdown()

		return srv.Shutdown(ctx)
	}
}