func()

in registry/handlers/app.go [871:1004]


func (app *App) RegisterHealthChecks(healthRegistries ...*health.Registry) error {
	logger := dcontext.GetLogger(app)

	if len(healthRegistries) > 1 {
		return fmt.Errorf("RegisterHealthChecks called with more than one registry")
	}

	// Allow for dependency injection:
	if len(healthRegistries) > 0 {
		app.healthRegistry = healthRegistries[0]
	} else {
		app.healthRegistry = health.DefaultRegistry
	}
	app.registerShutdownFunc(
		func(app *App, errCh chan error, l dlog.Logger) {
			l.Info("closing healthchecks registry")
			err := app.healthRegistry.Shutdown()
			if err != nil {
				err = fmt.Errorf("healthchecks registry shutdown: %w", err)
			} else {
				l.Info("healthchecks registry has been shut down")
			}
			errCh <- err
		},
	)

	if app.Config.Health.StorageDriver.Enabled {
		interval := app.Config.Health.StorageDriver.Interval
		if interval == 0 {
			interval = defaultCheckInterval
		}

		storageDriverCheck := func() error {
			_, err := app.driver.Stat(app, "/")
			if errors.As(err, new(storagedriver.PathNotFoundError)) {
				err = nil // pass this through, backend is responding, but this path doesn't exist.
			}
			if err != nil {
				logger.Errorf("storage driver health check: %v", err)
			}
			return err
		}

		logger.WithFields(
			dlog.Fields{
				"threshold":  app.Config.Health.StorageDriver.Threshold,
				"interval_s": interval.Seconds(),
			},
		).Info("configuring storage health check")
		if app.Config.Health.StorageDriver.Threshold != 0 {
			app.healthRegistry.RegisterPeriodicThresholdFunc("storagedriver_"+app.Config.Storage.Type(), interval, app.Config.Health.StorageDriver.Threshold, storageDriverCheck)
		} else {
			app.healthRegistry.RegisterPeriodicFunc("storagedriver_"+app.Config.Storage.Type(), interval, storageDriverCheck)
		}
	}

	if app.Config.Health.Database.Enabled {
		if !app.Config.Database.Enabled {
			logger.Warn("ignoring database health checks settings as metadata database is not enabled")
		} else {
			interval := app.Config.Health.Database.Interval
			if interval == 0 {
				interval = defaultCheckInterval
			}
			timeout := app.Config.Health.Database.Timeout
			if timeout == 0 {
				timeout = defaultDBCheckTimeout
			}

			check := checks.DBChecker(app.Context, timeout, app.db)

			logger.WithFields(
				dlog.Fields{
					"timeout":    timeout.String(),
					"interval_s": interval.Seconds(),
				},
			).Info("configuring database health check")
			if app.Config.Health.Database.Threshold != 0 {
				app.healthRegistry.RegisterPeriodicThresholdFunc("database_connection", interval, app.Config.Health.Database.Threshold, check)
			} else {
				app.healthRegistry.RegisterPeriodicFunc("database_connection", interval, check)
			}
		}
	}

	for _, fileChecker := range app.Config.Health.FileCheckers {
		interval := fileChecker.Interval
		if interval == 0 {
			interval = defaultCheckInterval
		}
		dcontext.GetLogger(app).Infof("configuring file health check path=%s, interval=%d", fileChecker.File, interval/time.Second)
		app.healthRegistry.Register(fileChecker.File, health.PeriodicChecker(checks.FileChecker(fileChecker.File), interval))
	}

	for _, httpChecker := range app.Config.Health.HTTPCheckers {
		interval := httpChecker.Interval
		if interval == 0 {
			interval = defaultCheckInterval
		}

		statusCode := httpChecker.StatusCode
		if statusCode == 0 {
			statusCode = 200
		}

		checker := checks.HTTPChecker(httpChecker.URI, statusCode, httpChecker.Timeout, httpChecker.Headers)

		if httpChecker.Threshold != 0 {
			dcontext.GetLogger(app).Infof("configuring HTTP health check uri=%s, interval=%d, threshold=%d", httpChecker.URI, interval/time.Second, httpChecker.Threshold)
			app.healthRegistry.Register(httpChecker.URI, health.PeriodicThresholdChecker(checker, interval, httpChecker.Threshold))
		} else {
			dcontext.GetLogger(app).Infof("configuring HTTP health check uri=%s, interval=%d", httpChecker.URI, interval/time.Second)
			app.healthRegistry.Register(httpChecker.URI, health.PeriodicChecker(checker, interval))
		}
	}

	for _, tcpChecker := range app.Config.Health.TCPCheckers {
		interval := tcpChecker.Interval
		if interval == 0 {
			interval = defaultCheckInterval
		}

		checker := checks.TCPChecker(tcpChecker.Addr, tcpChecker.Timeout)

		if tcpChecker.Threshold != 0 {
			dcontext.GetLogger(app).Infof("configuring TCP health check addr=%s, interval=%d, threshold=%d", tcpChecker.Addr, interval/time.Second, tcpChecker.Threshold)
			app.healthRegistry.Register(tcpChecker.Addr, health.PeriodicThresholdChecker(checker, interval, tcpChecker.Threshold))
		} else {
			dcontext.GetLogger(app).Infof("configuring TCP health check addr=%s, interval=%d", tcpChecker.Addr, interval/time.Second)
			app.healthRegistry.Register(tcpChecker.Addr, health.PeriodicChecker(checker, interval))
		}
	}
	return nil
}