Add lock to make sure only one ical_sync can run simultaneously
This commit is contained in:
parent
d78f69abe9
commit
ee2856c5fc
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -215,6 +215,7 @@ fabric.properties
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
venv/
|
venv/
|
||||||
|
static/
|
||||||
|
|
||||||
davinci/local.py
|
davinci/local.py
|
||||||
|
|
||||||
|
|
61
davinci/icalendar/decorators.py
Normal file
61
davinci/icalendar/decorators.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from lockfile import FileLock, AlreadyLocked, LockTimeout
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
# Lock timeout value - how long to wait for the lock to become available.
|
||||||
|
# Default behavior is to never wait for the lock to be available (fail fast)
|
||||||
|
LOCK_WAIT_TIMEOUT = getattr(settings, "DEFAULT_LOCK_WAIT_TIMEOUT", -1)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_lock(handle):
|
||||||
|
"""
|
||||||
|
Decorate the handle method with a file lock to ensure there is only ever
|
||||||
|
one process running at any one time.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapper(self, *args, **options):
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
verbosity = options.get('verbosity', 0)
|
||||||
|
if verbosity == 0:
|
||||||
|
level = logging.WARNING
|
||||||
|
elif verbosity == 1:
|
||||||
|
level = logging.INFO
|
||||||
|
else:
|
||||||
|
level = logging.DEBUG
|
||||||
|
|
||||||
|
logging.basicConfig(level=level, format="%(message)s")
|
||||||
|
logging.debug("-" * 72)
|
||||||
|
|
||||||
|
lock_name = self.__module__.split('.').pop()
|
||||||
|
lock = FileLock(lock_name)
|
||||||
|
|
||||||
|
logging.debug("%s - acquiring lock..." % lock_name)
|
||||||
|
try:
|
||||||
|
lock.acquire(LOCK_WAIT_TIMEOUT)
|
||||||
|
except AlreadyLocked:
|
||||||
|
logging.debug("lock already in place. quitting.")
|
||||||
|
return
|
||||||
|
except LockTimeout:
|
||||||
|
logging.debug("waiting for the lock timed out. quitting.")
|
||||||
|
return
|
||||||
|
logging.debug("acquired.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
handle(self, *args, **options)
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
logging.warning("Command Failed")
|
||||||
|
logging.warning('==' * 72)
|
||||||
|
logging.warning(traceback.format_exc())
|
||||||
|
logging.warning('==' * 72)
|
||||||
|
|
||||||
|
logging.debug("releasing lock...")
|
||||||
|
lock.release()
|
||||||
|
logging.debug("released.")
|
||||||
|
|
||||||
|
logging.info("done in %.2f seconds" % (time.time() - start_time))
|
||||||
|
|
||||||
|
return wrapper
|
|
@ -3,12 +3,14 @@ import logging
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from davinci.icalendar.decorators import handle_lock
|
||||||
from davinci.icalendar.models import ICalSync
|
from davinci.icalendar.models import ICalSync
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Sychronize iCal syncs that need to be synchronized.'
|
help = 'Sychronize iCal syncs that need to be synchronized.'
|
||||||
|
|
||||||
|
@handle_lock
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
logger = logging.getLogger("davinci.icalendar.ical_sync")
|
logger = logging.getLogger("davinci.icalendar.ical_sync")
|
||||||
logger.debug(f"Command `ical_sync` invoked")
|
logger.debug(f"Command `ical_sync` invoked")
|
||||||
|
|
|
@ -4,3 +4,4 @@ django-durationwidget>=1.0.5,<1.1
|
||||||
humanize>=3.1.0,<3.2
|
humanize>=3.1.0,<3.2
|
||||||
ics>=0.7,<0.8
|
ics>=0.7,<0.8
|
||||||
caldav>=0.7.1,<0.8
|
caldav>=0.7.1,<0.8
|
||||||
|
lockfile>=0.12.2,<0.13
|
||||||
|
|
Loading…
Reference in a new issue