Add Redis based distributed lock backend

- RedisLock backend requires one argument: "redis_url".
  Example: redis://127.0.0.1:6379/0

- Add the setting LOCK_MANAGER_BACKEND_ARGUMENTS.

Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-11-20 04:40:02 -04:00
parent 3b9245c029
commit 448176111b
4 changed files with 62 additions and 2 deletions

View File

@@ -169,6 +169,9 @@
- Add document type change API endpoint.
- Change OCR API submit URL from documents/{pk}/submit
to documents/{pk}/ocr/submit.
- Add Redis based distributed lock backend. Requires one
argument: "redis_url". Example: redis://127.0.0.1:6379/0
- Add the setting LOCK_MANAGER_BACKEND_ARGUMENTS.
3.3.11 (2019-XX-XX)
===================

View File

@@ -0,0 +1,43 @@
from __future__ import unicode_literals
import redis
from ..exceptions import LockError
from ..settings import setting_backend_arguments
from .base import LockingBackend
class RedisLock(LockingBackend):
@classmethod
def acquire_lock(cls, name, timeout=None):
super(RedisLock, cls).acquire_lock(name=name, timeout=timeout)
return RedisLock(name=name, timeout=timeout)
@classmethod
def get_redis_connection(cls):
redis_url = setting_backend_arguments.value.get('redis_url', None)
server = redis.from_url(url=redis_url)
server.client_id()
return server
@classmethod
def purge_locks(cls):
super(RedisLock, cls).purge_locks()
def __init__(self, name, timeout):
self.name = name
redis_lock_instance = self.get_redis_connection().lock(
name=name, timeout=timeout, sleep=0.1, blocking_timeout=0.1
)
if redis_lock_instance.acquire():
self.redis_lock_instance = redis_lock_instance
else:
raise LockError
def release(self):
super(RedisLock, self).release()
try:
self.redis_lock_instance.release()
except redis.exceptions.LockNotOwnedError:
return

View File

@@ -15,6 +15,10 @@ setting_backend = namespace.add_setting(
'resource locks.'
)
)
setting_backend_arguments = namespace.add_setting(
global_name='LOCK_MANAGER_BACKEND_ARGUMENTS',
default={}, help_text=_('Arguments to pass to the LOCK_MANAGER_BACKEND.')
)
setting_default_lock_timeout = namespace.add_setting(
default=DEFAULT_LOCK_TIMEOUT_VALUE,

View File

@@ -2,18 +2,21 @@ from __future__ import unicode_literals
import time
from django.test import TestCase
from django.test import override_settings
from django.utils.module_loading import import_string
from mayan.apps.common.tests.base import BaseTestCase
from ..exceptions import LockError
TEST_LOCK_1 = 'test lock 1'
class FileLockTestCase(TestCase):
class FileLockTestCase(BaseTestCase):
backend_string = 'mayan.apps.lock_manager.backends.file_lock.FileLock'
def setUp(self):
super(FileLockTestCase, self).setUp()
self.locking_backend = import_string(self.backend_string)
def test_exclusive(self):
@@ -72,3 +75,10 @@ class FileLockTestCase(TestCase):
class ModelLockTestCase(FileLockTestCase):
backend_string = 'mayan.apps.lock_manager.backends.model_lock.ModelLock'
@override_settings(
LOCK_MANAGER_BACKEND_ARGUMENTS={'redis_url': 'redis://127.0.0.1:6379/0'}
)
class RedisLockTestCase(FileLockTestCase):
backend_string = 'mayan.apps.lock_manager.backends.redis_lock.RedisLock'