From a0e68b8ca353236444ea8e228f1990c6c7bebbc6 Mon Sep 17 00:00:00 2001 From: fanchi Date: Wed, 28 Nov 2018 11:35:18 +0200 Subject: [PATCH] Add manage command run_with_lock The command will dynamically invoke another command specified in the following arguments patching its handle to use distributedlock and perfectly forward its arguments --- distributedlock/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/run_with_lock.py | 36 +++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 distributedlock/management/__init__.py create mode 100644 distributedlock/management/commands/__init__.py create mode 100644 distributedlock/management/commands/run_with_lock.py diff --git a/distributedlock/management/__init__.py b/distributedlock/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/distributedlock/management/commands/__init__.py b/distributedlock/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/distributedlock/management/commands/run_with_lock.py b/distributedlock/management/commands/run_with_lock.py new file mode 100644 index 0000000..a3a08f4 --- /dev/null +++ b/distributedlock/management/commands/run_with_lock.py @@ -0,0 +1,36 @@ +from django.core.management import ManagementUtility +from django.core.management.base import BaseCommand, CommandError +from distributedlock import distributedlock, LockNotAcquiredError +import types + + +class Command(BaseCommand): + """ + Dynamically invokes the command, patching its handle to use distributedlock and perfectly forwards arguments + usage example: + manage run_with_lock update_calendars --ignore-past + """ + + def handle(self, *args, **options): + pass + + help = 'A wrapper command that runs a manage command with a distributed lock.' + + def run_from_argv(self, argv): + try: + command_name = argv[2] + argv.pop(1) + utility = ManagementUtility(argv) + command_class = utility.fetch_command(command_name) + handle = command_class.handle + + def locking_handle(self, *args, **options): + with distributedlock(command_name): + handle(self, *args, **options) + + command_class.handle = types.MethodType(locking_handle, command_class) + command_class.run_from_argv(utility.argv) + except IndexError: + raise CommandError('Missing arguments') + except LockNotAcquiredError: + raise CommandError('%s command is already locked' % command_name)