Simplyfied and updated the lock manager app
This commit is contained in:
10
apps/lock_manager/admin.py
Normal file
10
apps/lock_manager/admin.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from lock_manager.models import Lock
|
||||||
|
|
||||||
|
|
||||||
|
class LockAdmin(admin.ModelAdmin):
|
||||||
|
model = Lock
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Lock, LockAdmin)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
DEFAULT_LOCK_TIMEOUT_VALUE = 10
|
DEFAULT_LOCK_TIMEOUT_VALUE = 30
|
||||||
|
|
||||||
DEFAULT_LOCK_TIMEOUT = getattr(settings, 'LOCK_MANAGER_DEFAULT_LOCK_TIMEOUT', DEFAULT_LOCK_TIMEOUT_VALUE)
|
DEFAULT_LOCK_TIMEOUT = getattr(settings, 'LOCK_MANAGER_DEFAULT_LOCK_TIMEOUT', DEFAULT_LOCK_TIMEOUT_VALUE)
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
try:
|
import logging
|
||||||
from psycopg2 import OperationalError
|
|
||||||
except ImportError:
|
|
||||||
class OperationalError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.db.utils import DatabaseError
|
from django.db.utils import DatabaseError
|
||||||
@@ -13,40 +8,33 @@ from django.db import models
|
|||||||
|
|
||||||
from lock_manager.exceptions import LockError
|
from lock_manager.exceptions import LockError
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LockManager(models.Manager):
|
class LockManager(models.Manager):
|
||||||
@transaction.commit_manually
|
@transaction.commit_on_success
|
||||||
def acquire_lock(self, name, timeout=None):
|
def acquire_lock(self, name, timeout=None):
|
||||||
|
logger.debug('DEBUG: trying to acquire lock: %s' % name)
|
||||||
lock = self.model(name=name, timeout=timeout)
|
lock = self.model(name=name, timeout=timeout)
|
||||||
try:
|
try:
|
||||||
lock.save(force_insert=True)
|
lock.save(force_insert=True)
|
||||||
|
logger.debug('DEBUG: acquired lock: %s' % name)
|
||||||
|
return lock
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
transaction.rollback()
|
|
||||||
# There is already an existing lock
|
# There is already an existing lock
|
||||||
# Check it's expiration date and if expired, delete it and
|
# Check it's expiration date and if expired, reset it
|
||||||
# create it again
|
try:
|
||||||
lock = self.model.objects.get(name=name)
|
lock = self.model.objects.get(name=name)
|
||||||
transaction.rollback()
|
except self.model.DoesNotExist:
|
||||||
|
# Table based locking
|
||||||
|
logger.debug('DEBUG: lock: %s does not exist' % name)
|
||||||
|
raise LockError('Unable to acquire lock')
|
||||||
|
|
||||||
if datetime.datetime.now() > lock.creation_datetime + datetime.timedelta(seconds=lock.timeout):
|
if datetime.datetime.now() > lock.creation_datetime + datetime.timedelta(seconds=lock.timeout):
|
||||||
self.release_lock(name)
|
logger.debug('DEBUG: reseting deleting stale lock: %s' % name)
|
||||||
lock.timeout=timeout
|
lock.timeout=timeout
|
||||||
|
logger.debug('DEBUG: try to reacquire stale lock: %s' % name)
|
||||||
lock.save()
|
lock.save()
|
||||||
transaction.commit()
|
return lock
|
||||||
else:
|
else:
|
||||||
raise LockError('Unable to acquire lock')
|
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()
|
|
||||||
|
|||||||
@@ -10,17 +10,28 @@ from lock_manager.conf.settings import DEFAULT_LOCK_TIMEOUT
|
|||||||
class Lock(models.Model):
|
class Lock(models.Model):
|
||||||
creation_datetime = models.DateTimeField(verbose_name=_(u'creation datetime'))
|
creation_datetime = models.DateTimeField(verbose_name=_(u'creation datetime'))
|
||||||
timeout = models.IntegerField(default=DEFAULT_LOCK_TIMEOUT, verbose_name=_(u'timeout'))
|
timeout = models.IntegerField(default=DEFAULT_LOCK_TIMEOUT, verbose_name=_(u'timeout'))
|
||||||
name = models.CharField(max_length=32, verbose_name=_(u'name'), unique=True)
|
name = models.CharField(max_length=48, verbose_name=_(u'name'), unique=True)
|
||||||
|
|
||||||
objects = LockManager()
|
objects = LockManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
self.creation_datetime = datetime.datetime.now()
|
self.creation_datetime = datetime.datetime.now()
|
||||||
|
if not self.timeout and not kwarget.get('timeout'):
|
||||||
|
self.timeout = DEFAULT_LOCK_TIMEOUT
|
||||||
|
|
||||||
super(Lock, self).save(*args, **kwargs)
|
super(Lock, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
def release(self):
|
||||||
|
try:
|
||||||
|
lock = Lock.objects.get(name=self.name, creation_datetime=self.creation_datetime)
|
||||||
|
lock.delete()
|
||||||
|
except Lock.DoesNotExist:
|
||||||
|
# Out lock expired and was reassigned
|
||||||
|
pass
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _(u'lock')
|
verbose_name = _(u'lock')
|
||||||
verbose_name_plural = _(u'locks')
|
verbose_name_plural = _(u'locks')
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
"""
|
|
||||||
This file demonstrates writing tests using the unittest module. These will pass
|
|
||||||
when you run "manage.py test".
|
|
||||||
|
|
||||||
Replace this with more appropriate tests for your application.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user