Add lock to make sure only one ical_sync can run simultaneously

This commit is contained in:
Kevin Alberts 2020-11-11 17:18:21 +01:00
parent d78f69abe9
commit ee2856c5fc
Signed by: Kurocon
GPG key ID: BCD496FEBA0C6BC1
4 changed files with 65 additions and 0 deletions

1
.gitignore vendored
View file

@ -215,6 +215,7 @@ fabric.properties
.idea/
venv/
static/
davinci/local.py

View 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

View file

@ -3,12 +3,14 @@ import logging
from django.core.management.base import BaseCommand
from django.utils import timezone
from davinci.icalendar.decorators import handle_lock
from davinci.icalendar.models import ICalSync
class Command(BaseCommand):
help = 'Sychronize iCal syncs that need to be synchronized.'
@handle_lock
def handle(self, *args, **options):
logger = logging.getLogger("davinci.icalendar.ical_sync")
logger.debug(f"Command `ical_sync` invoked")

View file

@ -4,3 +4,4 @@ django-durationwidget>=1.0.5,<1.1
humanize>=3.1.0,<3.2
ics>=0.7,<0.8
caldav>=0.7.1,<0.8
lockfile>=0.12.2,<0.13