diff --git a/apps/lock_manager/conf/__init__.py b/apps/lock_manager/conf/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/lock_manager/conf/settings.py b/apps/lock_manager/conf/settings.py new file mode 100644 index 0000000000..05f4ae374c --- /dev/null +++ b/apps/lock_manager/conf/settings.py @@ -0,0 +1,5 @@ +from django.conf import settings + +DEFAULT_LOCK_TIMEOUT_VALUE = 10 + +DEFAULT_LOCK_TIMEOUT = getattr(settings, 'LOCK_MANAGER_DEFAULT_LOCK_TIMEOUT', DEFAULT_LOCK_TIMEOUT_VALUE) diff --git a/apps/lock_manager/exceptions.py b/apps/lock_manager/exceptions.py new file mode 100644 index 0000000000..cede7b1642 --- /dev/null +++ b/apps/lock_manager/exceptions.py @@ -0,0 +1,2 @@ +class LockError(Exception): + pass diff --git a/apps/lock_manager/managers.py b/apps/lock_manager/managers.py new file mode 100644 index 0000000000..96c57ca02b --- /dev/null +++ b/apps/lock_manager/managers.py @@ -0,0 +1,52 @@ +try: + from psycopg2 import OperationalError +except ImportError: + class OperationalError(Exception): + pass + +import datetime + +from django.db.utils import DatabaseError +from django.db.utils import IntegrityError +from django.db import transaction +from django.db import models + +from lock_manager.exceptions import LockError + + +class LockManager(models.Manager): + @transaction.commit_manually + def acquire_lock(self, name, timeout=None): + lock = self.model(name=name, timeout=timeout) + try: + lock.save(force_insert=True) + except IntegrityError: + transaction.rollback() + # There is already an existing lock + # Check it's expiration date and if expired, delete it and + # create it again + lock = self.model.objects.get(name=name) + transaction.rollback() + + if datetime.datetime.now() > lock.creation_datetime + datetime.timedelta(seconds=lock.timeout): + self.release_lock(name) + lock.timeout=timeout + lock.save() + transaction.commit() + else: + raise LockError('Unable to acquire lock') + except DatabaseError: + transaction.rollback() + # Special case for ./manage.py syncdb + except (OperationalError, ImproperlyConfigured): + transaction.rollback() + # Special for DjangoZoom, which executes collectstatic media + # doing syncdb and creating the database tables + else: + transaction.commit() + + @transaction.commit_manually + def release_lock(self, name): + lock = self.model.objects.get(name=name) + lock.delete() + transaction.commit() diff --git a/apps/lock_manager/models.py b/apps/lock_manager/models.py index 56a2d3e483..53c6b6e49d 100644 --- a/apps/lock_manager/models.py +++ b/apps/lock_manager/models.py @@ -2,42 +2,14 @@ import datetime from django.db import models from django.utils.translation import ugettext_lazy as _ -from django.db.utils import IntegrityError -from django.db import transaction +from lock_manager.managers import LockManager +from lock_manager.conf.settings import DEFAULT_LOCK_TIMEOUT -class LockError(Exception): - pass - -class LockManager(models.Manager): - @transaction.commit_manually - def acquire_lock(self, name): - lock = self.model(name=name) - try: - lock.save(force_insert=True) - except IntegrityError: - transaction.rollback() - # There is already an existing lock - # Check it's expiration date and if expired delete it and - # re-create it - lock = Lock.objects.get(name=name) - if datetime.datetime.now() > lock.creation_datetime + datetime.timedelta(seconds=lock.expiration): - release_lock(self) - lock.save() - else: - raise LockError('Unable to acquire lock') - else: - transaction.commit() - - @transaction.commit_manually - def release_lock(self, name): - lock = Lock.objects.get(name=name) - lock.delete() - transaction.commit() class Lock(models.Model): creation_datetime = models.DateTimeField(verbose_name=_(u'creation datetime')) - expiration_time = models.IntegerField(default=3600, verbose_name=_(u'expiration time')) + timeout = models.IntegerField(default=DEFAULT_LOCK_TIMEOUT, verbose_name=_(u'timeout')) name = models.CharField(max_length=32, verbose_name=_(u'name'), unique=True) objects = LockManager()