diff --git a/internal/bootstrap/service_bootstrap.go b/internal/bootstrap/service_bootstrap.go index bf94c5c4..9490b00b 100644 --- a/internal/bootstrap/service_bootstrap.go +++ b/internal/bootstrap/service_bootstrap.go @@ -8,7 +8,7 @@ import ( ) func (app *BootstrapApp) setupServices() error { - ldapService, err := service.NewLdapService(app.log, app.config, app.ding) + ldapService, err := service.NewLdapService(app.log, app.config, app.ctx, app.ding) if err != nil { app.log.App.Warn().Err(err).Msg("Failed to initialize LDAP connection, will continue without it") diff --git a/internal/service/ldap_service.go b/internal/service/ldap_service.go index cb0f0f5a..9254e5f5 100644 --- a/internal/service/ldap_service.go +++ b/internal/service/ldap_service.go @@ -17,6 +17,7 @@ import ( type LdapService struct { log *logger.Logger config model.Config + ctx context.Context conn *ldapgo.Conn mutex sync.RWMutex @@ -26,6 +27,7 @@ type LdapService struct { func NewLdapService( log *logger.Logger, config model.Config, + ctx context.Context, dg *ding.Ding, ) (*LdapService, error) { if config.LDAP.Address == "" { @@ -35,6 +37,7 @@ func NewLdapService( ldap := &LdapService{ log: log, config: config, + ctx: ctx, } // Check whether authentication with client certificate is possible @@ -63,7 +66,9 @@ func NewLdapService( _, err := ldap.connect() + // Warn: This will hang the tinyauth startup for a good 45 seconds until it fails if err != nil { + err = ldap.reconnect(10 * time.Second) return nil, fmt.Errorf("failed to connect to ldap server: %w", err) } @@ -79,7 +84,7 @@ func NewLdapService( err := ldap.heartbeat() if err != nil { ldap.log.App.Warn().Err(err).Msg("LDAP connection heartbeat failed, attempting to reconnect") - if reconnectErr := ldap.reconnect(); reconnectErr != nil { + if reconnectErr := ldap.reconnect(5 * time.Second); reconnectErr != nil { ldap.log.App.Error().Err(reconnectErr).Msg("Failed to reconnect to LDAP server") continue } @@ -247,17 +252,19 @@ func (ldap *LdapService) heartbeat() error { return nil } -func (ldap *LdapService) reconnect() error { +func (ldap *LdapService) reconnect(interval time.Duration) error { ldap.log.App.Info().Msg("Attempting to reconnect to LDAP server") exp := backoff.NewExponentialBackOff() - exp.InitialInterval = 500 * time.Millisecond + exp.InitialInterval = interval exp.RandomizationFactor = 0.1 exp.Multiplier = 1.5 exp.Reset() operation := func() (*ldapgo.Conn, error) { - ldap.conn.Close() + if ldap.conn != nil { + ldap.conn.Close() + } conn, err := ldap.connect() if err != nil { return nil, err @@ -265,7 +272,7 @@ func (ldap *LdapService) reconnect() error { return conn, nil } - _, err := backoff.Retry(context.TODO(), operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3)) + _, err := backoff.Retry(ldap.ctx, operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3)) if err != nil { return err