providers/scim, sources/ldap: switch to using postgres advisory locks instead of redis locks (#9511)
* providers/scim, sources/ldap: switch to using postgres advisory locks instead of redis locks Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> * website/integrations: discord: fix typo Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> * fix timeout logic Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> * remove redis locks completely Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> * Apply suggestions from code review Signed-off-by: Jens L. <jens@beryju.org> --------- Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> Signed-off-by: Jens L. <jens@beryju.org> Co-authored-by: Jens L <jens@goauthentik.io>
This commit is contained in:
committed by
GitHub
parent
fbab822db1
commit
fbad02fac1
@ -6,19 +6,19 @@ from shutil import rmtree
|
||||
from ssl import CERT_REQUIRED
|
||||
from tempfile import NamedTemporaryFile, mkdtemp
|
||||
|
||||
from django.core.cache import cache
|
||||
import pglock
|
||||
from django.db import connection, models
|
||||
from django.templatetags.static import static
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from ldap3 import ALL, NONE, RANDOM, Connection, Server, ServerPool, Tls
|
||||
from ldap3.core.exceptions import LDAPException, LDAPInsufficientAccessRightsResult, LDAPSchemaError
|
||||
from redis.lock import Lock
|
||||
from rest_framework.serializers import Serializer
|
||||
|
||||
from authentik.core.models import Group, PropertyMapping, Source
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.lib.config import CONFIG
|
||||
from authentik.lib.models import DomainlessURLValidator
|
||||
from authentik.lib.sync.outgoing import LOCK_ACQUIRE_TIMEOUT
|
||||
|
||||
LDAP_TIMEOUT = 15
|
||||
|
||||
@ -209,15 +209,12 @@ class LDAPSource(Source):
|
||||
return RuntimeError("Failed to bind")
|
||||
|
||||
@property
|
||||
def sync_lock(self) -> Lock:
|
||||
"""Redis lock for syncing LDAP to prevent multiple parallel syncs happening"""
|
||||
return Lock(
|
||||
cache.client.get_client(),
|
||||
name=f"goauthentik.io/sources/ldap/sync/{connection.schema_name}-{self.slug}",
|
||||
# Convert task timeout hours to seconds, and multiply times 3
|
||||
# (see authentik/sources/ldap/tasks.py:54)
|
||||
# multiply by 3 to add even more leeway
|
||||
timeout=(60 * 60 * CONFIG.get_int("ldap.task_timeout_hours")) * 3,
|
||||
def sync_lock(self) -> pglock.advisory:
|
||||
"""Postgres lock for syncing LDAP to prevent multiple parallel syncs happening"""
|
||||
return pglock.advisory(
|
||||
lock_id=f"goauthentik.io/{connection.schema_name}/sources/ldap/sync/{self.slug}",
|
||||
timeout=LOCK_ACQUIRE_TIMEOUT,
|
||||
side_effect=pglock.Raise,
|
||||
)
|
||||
|
||||
def check_connection(self) -> dict[str, dict[str, str]]:
|
||||
|
||||
@ -4,8 +4,8 @@ from uuid import uuid4
|
||||
|
||||
from celery import chain, group
|
||||
from django.core.cache import cache
|
||||
from django.db.utils import OperationalError
|
||||
from ldap3.core.exceptions import LDAPException
|
||||
from redis.exceptions import LockError
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.events.models import SystemTask as DBSystemTask
|
||||
@ -64,12 +64,8 @@ def ldap_sync_single(source_pk: str):
|
||||
source: LDAPSource = LDAPSource.objects.filter(pk=source_pk).first()
|
||||
if not source:
|
||||
return
|
||||
lock = source.sync_lock
|
||||
if lock.locked():
|
||||
LOGGER.debug("LDAP sync locked, skipping task", source=source.slug)
|
||||
return
|
||||
try:
|
||||
with lock:
|
||||
with source.sync_lock:
|
||||
# Delete all sync tasks from the cache
|
||||
DBSystemTask.objects.filter(name="ldap_sync", uid__startswith=source.slug).delete()
|
||||
task = chain(
|
||||
@ -84,10 +80,8 @@ def ldap_sync_single(source_pk: str):
|
||||
),
|
||||
)
|
||||
task()
|
||||
except LockError:
|
||||
# This should never happen, we check if the lock is locked above so this
|
||||
# would only happen if there was some other timeout
|
||||
LOGGER.debug("Failed to acquire lock for LDAP sync", source=source.slug)
|
||||
except OperationalError:
|
||||
LOGGER.debug("Failed to acquire lock for LDAP sync, skipping task", source=source.slug)
|
||||
|
||||
|
||||
def ldap_sync_paginator(source: LDAPSource, sync: type[BaseLDAPSynchronizer]) -> list:
|
||||
|
||||
Reference in New Issue
Block a user